How to run command in cron job with external string - linux

I need to run corn job every month to update software license.
The license is ready in text file on remote server (example: http://codebox.ir/soft/license.txt) and update every month.
license.txt content Example "tev3vv5-v343".
I want to grab the license and put in some command:
# update xxxx-xxxx
how can I make this?
CentOs 6.4

Write a script which fetches the file from your remoteserver
wget http://codebox.ir/soft/license.txt
Then you get the key out of that textfile and pipe it into your updatecommand
update `cat license.txt`
note the Backticks, so your script could look like this
#!/bin/sh
#
# This script fetches and updates the licensefile
#
wget http://codebox.ir/soft/license.txt;
update `cat license.txt`;
make the file executable
chmod +x updateLicense.sh
and put it in your crontab
cd /path/to/script;./updateLicense.sh
or to keep it compact, allthough i would check if the file is in an expected format first.
#!/bin/sh
#
# This script fetches and updates the licensefile
#
update `wget http://codebox.ir/soft/license.txt`;
And with checking if fetch succeeded
#!/bin/sh
#
# This script fetches and updates the licensefile
#
URL = http://codebox.ir/soft/license.txt
wget_output=$(wget -q "$URL")
if [ $? -ne 0 ]; then
update $wget_output
fi
No you can develop it further, i'd advise to check the format of the key before updating
#!/bin/sh
#
# This script fetches and updates the licensefile
#
# Define URL
URL = http://codebox.ir/soft/license.txt
# Fetch content
wget_output=$(wget -q "$URL")
# Check if fetch suceeded $? is the returnvalue of wget in this case
if [ $? -ne 0 ]; then
# Use mad Regexskillz to check format of licensekey and update if matched
if [[ $wget_output == [a-z0-9]+-[a-z0-9]+ ]] ; then update $wget_output; fi
fi
I'd also return some values to further raise quality of your script, also i'd pass the url and the regex into the function to keep the script reusable but that's a matter of taste

Related

Advice with Bash script to perform actions on certain conditions

I have written part of a small (hopefully) simple script that checks a URL for an error being returned using wget. It then outputs the error to a log file for alerting purposes. What I then want to do is for a service to be restarted automatically.
I will be running this check via a cronjob every minute, so if there is still an error after the service has been restarted already, I don't want the script to restart the service again.
Is there a elegant way to achieve this?
This is what I have so far, a wget check, if error code 5, output to the health.log file and restart nginx, however, I don't want this looping around restarting nginx every 60 seconds when running on a cronjob.
#!bin/bash
URL='http://some-url-here/'
LOG='/var/log/nginx/health.log'
wget -q $URL
if [ $? = 5 ] ; then
echo "$(date). SSL Error." > $LOG
sudo service nginx restart
exit
fi
Assumptions:
it's ok if we create a new file (restart.log), otherwise we could append a new line to $LOG
we'll only perform a restart attempt every 10 minutes (aka 600 seconds)
OP wants to append to the current $LOG (current code overwrites/replaces the entire file each time the script runs)
Proposed method:
use a new file to store the epoch time at which the last restart was attempted
before trying a restart we compare the current epoch with the saved epoch and only proceed (with the restart) if the difference in epochs is greater than 600 seconds
Modifying OP's current script:
#!/bin/bash # add "/" at start of shebang path
URL='http://some-url-here/'
LOG='/var/log/nginx/health.log'
RLOG='/var/log/nginx/restart.log'
touch "$RLOG"
wget -q $URL
if [ $? = 5 ] ; then
echo "$(date). SSL Error." >> "$LOG" # replace ">" with ">>" so that we append to $LOG
read -r prev_epoch < <(tail -1 "$RLOG") # retrieve epoch of last restart attempt
prev_epoch="${prev_epoch:-0}" # default to 0 if there is nothing in the file
printf -v curr_epoch '%(%s)T' # use printf builtin to grab current epoch and save in variable 'curr_epoch'
# curr_epoch=$((date '+%s')) # uncomment if 'printf -v' is not available in your system
delta=$((curr_epoch - prev_epoch))
if [[ "${delta}" -gt 600 ]] ; then
sudo service nginx restart
echo "${curr_epoch}" > "$RLOG" # replace ">" with ">>" if you want to maintain a history of restart epochs; the "tail -1" should insure we only grab the 'last' entry
exit
else
echo "it has only been ${delta} seconds since last restart attempt; skipping restart" >> "$LOG"
fi
fi

Run script in a new screen if true

I have a script where it will check if background_logging is true, if it is then I want the rest of the script to run in a new detached screen.
I have tried using this: exec screen -dmS "alt-logging" /bin/bash "$0";. This will sometimes create the screen, etc. but other times nothing will happen at all. When it does create a screen, it doesn't run the rest of the script file and when I try to resume the screen it says it's (Dead??).
Here is the entire script, I have added some comments to explain better what I want to do:
#!/bin/bash
# Configuration files
config='config.cfg'
source "$config"
# If this is true, run the rest of the script in a new screen.
# $background_logging comes from the configuration file declared above (config).
if [ $background_logging == "true" ]; then
exec screen -dmS "alt-logging" /bin/bash "$0";
fi
[ $# -eq 0 ] && { echo -e "\nERROR: You must specify an alt file!"; exit 1; }
# Logging script
y=0
while IFS='' read -r line || [[ -n "$line" ]]; do
cmd="screen -dmS alt$y bash -c 'exec $line;'"
eval $cmd
sleep $logging_speed
y=$(( $y + 1 ))
done < "$1"
Here are the contents of the configuration file:
# This is the speed at which alts will be logged, set to 0 for fast launch.
logging_speed=5
# This is to make a new screen in which the script will run.
background_logging=true
The purpose of this script is to loop through each line in a text file and execute the line as a command. It works perfectly fine when $background_logging is false so there are no issues with the while loop.
As described, it's not entirely possible. Specifically what is going on in your script: when you exec you replace your running script code with that of screen.
What you could do though is to start screen, figure out few details about it and redirect your console scripts in/output to it, but you won't be able to reparent your running script to the screen process as if started there. Something like for instance:
#!/bin/bash
# Use a temp file to pass cat's parent pid out of screen.
tempfile=$(tempfile)
screen -dmS 'alt-logging' /bin/bash -c "echo \$\$ > \"${tempfile}\" && /bin/cat"
# Wait to receive that information on the outside (it may not be available
# immediately).
while [[ -z "${child_cat_pid}" ]] ; do
child_cat_pid=$(cat "${tempfile}")
done
# point stdin/out/err of the current shell (rest of the script) to that cat
# child process
exec 0< /proc/${child_cat_pid}/fd/0
exec 1> /proc/${child_cat_pid}/fd/1
exec 2> /proc/${child_cat_pid}/fd/2
# Rest of the script
i=0
while true ; do
echo $((i++))
sleep 1
done
Far from perfect and rather messy. It could probably be helped by using a 3rd party tool like reptyr to grab console of the script from inside the screen. But cleaner/simpler yet would be to (when desired) start the code that should be executed in that screen session after it has been established.
That said. I'd actually suggest to take a step back and ask, what exactly is it that you're trying to achieve and why exactly would you like to run your script in screen. Are you planning to attach/detach to/from it? Because if running a long term process with a detached console is what you are after, nohup might be a bit simpler route to go.

How can I send commands to msfconsole from shell?

Hi guys i need a shell script that can open for example msfconsole and then type commands in it, i made a very basic script but of course it stops when msfconsole starts... can you give me some example?
thanks!
this is the basic dumb script i made:
#!/bin/bash
service postgresql start && sleep 4 && msfconsole && sleep 15 && quit
As you can see i first start postgresql and then i start msfconsole and when i try to close it i can't because i'm not in the shell but im into metasploit.
If you want commands in your script to be read by msfconsole, you need to direct them to its stdin; otherwise, they're only read by the shell itself (which is waiting for msfconsole to exit before it proceeds).
One way to redirect a set of text to a given command is with a heredoc:
#!/bin/bash
service postgresql start || exit
msfconsole <<EOF
sleep 15
quit
EOF
I am not familiar with msfconsole but if you execute it then you get a prompt to enter commands then the following method I use to partition may ssd with gdisk, may work for you.
#!/bin/sh
(
# Delete current partition table
echo o # Delete partition table
echo Y # Confirm deletion
# Create Linux LVM partition
echo n # Create new partition
echo 3 # Partition number
echo # First Sector
echo # Last Sector
echo 8E00 # Set partition type: Linux LVM
# Write out partition table
echo w # Write out new partition table
echo Y # Confirm write
) | gdisk /dev/sdx
If you have space in the commands "" needed like: echo "ls -ltr"

How to run inotifywait continuously and run it as a cron or deamon?

I've built a shell script that uses inotifywait to automatically detect file changes on a specific directory. When a new PDF file is dropped in the directory this script should go off and it should then trigger ocropus-parser to execute some commands on it. The code:
#!/bin/sh
inotifywait -m ~/Desktop/PdfFolder -e create -e moved_to |
while read path action file; do
#echo "The file '$file' appeared in directory '$path' via '$action'"
# Check if the file is a PDF or another file type.
if [ $(head -c 4 "$file") = "%PDF" ]; then
echo "PDF found - filename: " + $file
python ocropus-parser.py $file
else
echo "NOT A PDF!"
fi
done
This works pretty well when I run this script through the terminal with ./filenotifier.sh but when I reboot my Linux (Ubuntu 14.04) my shell will no longer run and it will not restart after a reboot.
I've decided to create an init script that starts at boot time (I think). I did this by copying the file filenotifier.sh to init.d:
sudo cp ~/Desktop/PdfFolder/filenotifier.sh /etc/init.d/
I've then gave the file the correct rights:
sudo chmod 775 /etc/init.d/filenotifier.sh
and finally I've added the file to update-rc.d:
sudo update-rc.d filenotifier.sh defaults
However when I reboot and drop a PDF in the folder ~/Desktop/PdfFolder nothing will happen and it seems that the script does not go off.
I'm really not experienced with init.d, update-rc.d and deamon so I'm not sure what is wrong and if this is even a good approach or not.
Thanks,
Yenthe
Being an init-script, you should add the LSB header to your script, like this:
#!/bin/sh
### BEGIN INIT INFO
# Provides: filenotifier
# Required-Start: $remote_fs $syslog
# Required-Stop: $remote_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Something
# Description: Something else
### END INIT INFO
inotifywait -m ...
This way, you can ensure that your script runs when all mount points are available (thanks to Required-Start: $remote_fs). This is essential if your home directory is not on the root partition.
Another problem is that in your init-script you're using ~:
inotifywait -m ~/Desktop/PdfFolder ...
The ~ expands to the current user home directory. Init-scripts are run as root, so it'll expand to /root/Desktop/PdfFolder. Use ~<username> instead:
inotifywait -m ~yenthe/Desktop/PdfFolder ...
(Assuming that your username is yenthe.)
Or perhaps switch user before starting (using sudo).
$file is the basename without the path to the directory. Use "$path/$file" in your commands:
"$(head -c 4 "$path/$file")"
python ocropus-parser.py "$path/$file"
Maybe consider using name instead of file, to avoid confusion.
If things are not working, or if in general you want to investigate something, remember to use ps, like this:
ps -ef | grep inotifywait
ps will tell you, for example, whether your script is running and if inotifywait was launched with the correct arguments.
Last but not least: use "$file", not $file; use "$(head -c 4 "$file")", not $(head -c 4 "$file"); use read -r, not read. These tips can save you a lot of headaches in the future!
For that purpose the developers of inotify created incron. It is a cron like daemon which executes scripts based on changes in a watched file/directory rather than on time events.

Test a weekly cron job [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about a specific programming problem, a software algorithm, or software tools primarily used by programmers. If you believe the question would be on-topic on another Stack Exchange site, you can leave a comment to explain where the question may be able to be answered.
Closed 4 years ago.
Improve this question
I have a #!/bin/bash file in cron.week directory.
Is there a way to test if it works? Can't wait 1 week
I am on Debian 6 with root
Just do what cron does, run the following as root:
run-parts -v /etc/cron.weekly
... or the next one if you receive the "Not a directory: -v" error:
run-parts /etc/cron.weekly -v
Option -v prints the script names before they are run.
A wee bit beyond the scope of your question... but here's what I do.
The "how do I test a cron job?" question is closely connected to "how do I test scripts that run in non-interactive contexts launched by other programs?" In cron, the trigger is some time condition, but lots of other *nix facilities launch scripts or script fragments in non-interactive ways, and often the conditions in which those scripts run contain something unexpected and cause breakage until the bugs are sorted out. (See also: https://stackoverflow.com/a/17805088/237059 )
A general approach to this problem is helpful to have.
One of my favorite techniques is to use a script I wrote called 'crontest'. It launches the target command inside a GNU screen session from within cron, so that you can attach with a separate terminal to see what's going on, interact with the script, even use a debugger.
To set this up, you would use "all stars" in your crontab entry, and specify crontest as the first command on the command line, e.g.:
* * * * * crontest /command/to/be/tested --param1 --param2
So now cron will run your command every minute, but crontest will ensure that only one instance runs at a time. If the command takes time to run, you can do a "screen -x" to attach and watch it run. If the command is a script, you can put a "read" command at the top to make it stop and wait for the screen attachment to complete (hit enter after attaching)
If your command is a bash script, you can do this instead:
* * * * * crontest --bashdb /command/to/be/tested --param1 --param2
Now, if you attach with "screen -x", you'll be facing an interactive bashdb session, and you can step through the code, examine variables, etc.
#!/bin/bash
# crontest
# See https://github.com/Stabledog/crontest for canonical source.
# Test wrapper for cron tasks. The suggested use is:
#
# 1. When adding your cron job, use all 5 stars to make it run every minute
# 2. Wrap the command in crontest
#
#
# Example:
#
# $ crontab -e
# * * * * * /usr/local/bin/crontest $HOME/bin/my-new-script --myparams
#
# Now, cron will run your job every minute, but crontest will only allow one
# instance to run at a time.
#
# crontest always wraps the command in "screen -d -m" if possible, so you can
# use "screen -x" to attach and interact with the job.
#
# If --bashdb is used, the command line will be passed to bashdb. Thus you
# can attach with "screen -x" and debug the remaining command in context.
#
# NOTES:
# - crontest can be used in other contexts, it doesn't have to be a cron job.
# Any place where commands are invoked without an interactive terminal and
# may need to be debugged.
#
# - crontest writes its own stuff to /tmp/crontest.log
#
# - If GNU screen isn't available, neither is --bashdb
#
crontestLog=/tmp/crontest.log
lockfile=$(if [[ -d /var/lock ]]; then echo /var/lock/crontest.lock; else echo /tmp/crontest.lock; fi )
useBashdb=false
useScreen=$( if which screen &>/dev/null; then echo true; else echo false; fi )
innerArgs="$#"
screenBin=$(which screen 2>/dev/null)
function errExit {
echo "[-err-] $#" | tee -a $crontestLog >&2
}
function log {
echo "[-stat-] $#" >> $crontestLog
}
function parseArgs {
while [[ ! -z $1 ]]; do
case $1 in
--bashdb)
if ! $useScreen; then
errExit "--bashdb invalid in crontest because GNU screen not installed"
fi
if ! which bashdb &>/dev/null; then
errExit "--bashdb invalid in crontest: no bashdb on the PATH"
fi
useBashdb=true
;;
--)
shift
innerArgs="$#"
return 0
;;
*)
innerArgs="$#"
return 0
;;
esac
shift
done
}
if [[ -z $sourceMe ]]; then
# Lock the lockfile (no, we do not wish to follow the standard
# advice of wrapping this in a subshell!)
exec 9>$lockfile
flock -n 9 || exit 1
# Zap any old log data:
[[ -f $crontestLog ]] && rm -f $crontestLog
parseArgs "$#"
log "crontest starting at $(date)"
log "Raw command line: $#"
log "Inner args: $#"
log "screenBin: $screenBin"
log "useBashdb: $( if $useBashdb; then echo YES; else echo no; fi )"
log "useScreen: $( if $useScreen; then echo YES; else echo no; fi )"
# Were building a command line.
cmdline=""
# If screen is available, put the task inside a pseudo-terminal
# owned by screen. That allows the developer to do a "screen -x" to
# interact with the running command:
if $useScreen; then
cmdline="$screenBin -D -m "
fi
# If bashdb is installed and --bashdb is specified on the command line,
# pass the command to bashdb. This allows the developer to do a "screen -x" to
# interactively debug a bash shell script:
if $useBashdb; then
cmdline="$cmdline $(which bashdb) "
fi
# Finally, append the target command and params:
cmdline="$cmdline $innerArgs"
log "cmdline: $cmdline"
# And run the whole schlock:
$cmdline
res=$?
log "Command result: $res"
echo "[-result-] $(if [[ $res -eq 0 ]]; then echo ok; else echo fail; fi)" >> $crontestLog
# Release the lock:
9<&-
fi
After messing about with some stuff in cron which wasn't instantly compatible I found that the following approach was nice for debugging:
crontab -e
* * * * * /path/to/prog var1 var2 &>>/tmp/cron_debug_log.log
This will run the task once a minute and you can simply look in the /tmp/cron_debug_log.log file to figure out what is going on.
It is not exactly the "fire job" you might be looking for, but this helped me a lot when debugging a script that didn't work in cron at first.
I'd use a lock file and then set the cron job to run every minute. (use crontab -e and * * * * * /path/to/job) That way you can just keep editing the files and each minute they'll be tested out. Additionally, you can stop the cronjob by just touching the lock file.
#!/bin/sh
if [ -e /tmp/cronlock ]
then
echo "cronjob locked"
exit 1
fi
touch /tmp/cronlock
<...do your regular cron here ....>
rm -f /tmp/cronlock
What about putting it into cron.hourly, waiting until the next run of hourly cron jobs, then removing it? That would run it once within an hour, and in the cron environment. You can also run ./your_script, but that won't have the same environment as under cron.
Aside from that you can also use:
http://pypi.python.org/pypi/cronwrap
to wrap up your cron to send you an email upon success or failure.
None of these answers fit my specific situation, which was that I wanted to run one specific cron job, just once, and run it immediately.
I'm on a Ubuntu server, and I use cPanel to setup my cron jobs.
I simply wrote down my current settings, and then edited them to be one minute from now. When I fixed another bug, I just edited it again to one minute from now. And when I was all done, I just reset the settings back to how they were before.
Example: It's 4:34pm right now, so I put 35 16 * * *, for it to run at 16:35.
It worked like a charm, and the most I ever had to wait was a little less than one minute.
I thought this was a better option than some of the other answers because I didn't want to run all of my weekly crons, and I didn't want the job to run every minute. It takes me a few minutes to fix whatever the issues were before I'm ready to test it again. Hopefully this helps someone.
The solution I am using is as follows:
Edit crontab(use command :crontab -e) to run the job as frequently
as needed (every 1 minute or 5 minutes)
Modify the shell script which should be executed using cron to prints the output into some file (e.g: echo "Working fine" >>
output.txt)
Check the output.txt file using the command : tail -f output.txt, which will print the latest additions into this file, and thus you can track the execution of the script
I normally test by running the job i created like this:
It is easier to use two terminals to do this.
run job:
#./jobname.sh
go to:
#/var/log and run
run the following:
#tailf /var/log/cron
This allows me to see the cron logs update in real time. You can also review the log after you run it, I prefer watching in real time.
Here is an example of a simple cron job. Running a yum update...
#!/bin/bash
YUM=/usr/bin/yum
$YUM -y -R 120 -d 0 -e 0 update yum
$YUM -y -R 10 -e 0 -d 0 update
Here is the breakdown:
First command will update yum itself and next will apply system updates.
-R 120 : Sets the maximum amount of time yum will wait before performing a command
-e 0 : Sets the error level to 0 (range 0 - 10). 0 means print only critical errors about which you must be told.
-d 0 : Sets the debugging level to 0 - turns up or down the amount of things that are printed. (range: 0 - 10).
-y : Assume yes; assume that the answer to any question which would be asked is yes
After I built the cron job I ran the below command to make my job executable.
#chmod +x /etc/cron.daily/jobname.sh
Hope this helps,
Dorlack
sudo run-parts --test /var/spool/cron/crontabs/
files in that crontabs/ directory needs to be executable by owner - octal 700
source: man cron and NNRooth's
I'm using Webmin because its a productivity gem for someone who finds command line administration a bit daunting and impenetrable.
There is a "Save and Run Now" button in the "System > Scheduled Cron Jobs > Edit Cron Job" web interface.
It displays the output of the command and is exactly what I needed.

Resources