How to make multiple commands executed sequentially in atd - linux

echo "echo `date +'%Y%m%d-%H%M%S'`' hello' >> tmp.log;
sleep 3s;
echo `date +'%Y%m%d-%H%M%S'`' world' >> tmp.log" |
at now
I hope that these 3 commands will be executed in sequence use atd, but it is counterproductive. The 3 commands are executed in parallel. How can I execute these 3 commands in sequence?

atd does run commands sequentially, the problem is that both date commands run at the time you submit the job due to expansion, try :
#!/usr/bin/env bash
echo 'date +"%Y%m%d-%H%M%S hello" > /tmp/at.log;
sleep 3s;
date +"%Y%m%d-%H%M%S world" >> /tmp/at.log' |
at now

Related

Delete a newly created file using shell script after 5 minutes

I am writing a shell script where I create a file ABC.txt in a path /path/to/ABC/ABC.txt.
Now I at the end of the script, I want to schedule a cron job to delete this file after 5 minutes (just once, not recurring).
I cannot ad sleep of 5 minutes in this script as it is being used by multiple users on server for multiple paths/files. And 5 minutes after the user executes this script the corresponding file.txt from respective path should get deleted.
What I read from a cronjob is you can trigger a script using crontab -e and then providing periodic notation of job and path to script H/5 * * * * /bin/sh /path/to/ABC/ABC.txt.
Can someone tell me how to schedule such functionality using cron. If there is a better way to do this please suggest.
Using at command:
#!/usr/bin/env bash
script_path="$(realpath -s -- "$0")"
# start script
...
# end script
echo "rm -- \"$script_path\"" | at "now + 5 minutes"
Using background process with sleep:
#!/usr/bin/env bash
script_path="$(realpath -s -- "$0")"
# start script
...
# end script
( sleep 300 && rm -- "$script_path" ) &
Using parent selfdestruct process:
Write a little script selfdestruct that looks like:
#!/usr/bin/env bash
dt="$1"; shift
"$#"
( sleep "$dt" && rm -- "$1" ) &
and run your script with
$ selfdestruct 300 /path/to/script arg1 arg2 arg3

script to log the completion of an LSF (bsub) job

I have a script called by cron to run an LSF job.
I would like to be told when that job is submitted and when it completes. The-Powers-That-Be have decided to disable email notifications. So I am writing this script to output the relevant information to a logfile.
It almost works. Here is some code:
crontab:
00 12 * * * my_script.sh my_job.bsub
my_job.bsub:
#!/bin/bash
#BSUB -q my_queue
#BSUB -W 06:00
echo "I am a long process"
sleep 60
my_script.sh:
#!/bin/sh
BSUB_SCRIPT=$1
# run bsub_script (and get the LSF job id while you're at it)...
JOB_ID=`bsub < $BSUB_SCRIPT | awk -F[\<,\>] '{print $2}'`
# log that job was submitted...
echo "`date +%Y-%m%d %T` submitted '$BSUB_SCRIPT' [$JOB_ID]" >> $HOME/my_logfile.txt
# and log when job completes...
bsub -w "ended($JOB_ID)" << EOF
#!/bin/bash
#BSUB -q my_queue
#BSUB -W 00:30
echo "`date +%Y-%m-%d %T` completed '$BSUB_SCRIPT' [$JOB_ID]" >> $HOME/my_logfile.txt
EOF
(I found this answer helpful in figuring out how to submit a job that waits until an earlier one has completed.)
The issue is that the 2nd call to date, in the heredoc, gets evaluated immediately, so I wind up with a logfile that looks like this:
my_logfile.txt:
2018-01-30 13:15:14 submitted 'my_job.bsub' [1234567]
2018-01-30 13:15:14 completed 'my_job.bsub' [1234567]
Notice how the times are exactly the same.
How can I ensure that evaluation of the content of the heredoc is deferred until the LSF job runs?
The date command in the heredoc is being expanded before being passed to bsub. You need to quote the EOF in your heredoc expression or escape the date command. See the answer to this question:
How does "cat << EOF" work in bash?
In particular:
The format of here-documents is:
<<[-]word
here-document
delimiter
...
If word is unquoted, all lines of the here-document are
subjected to parameter expansion, command substitution, and arithmetic
expansion.
So, for example when I run
$ cat << EOF
> echo `date`
> EOF
The output is
echo Tue Jan 30 11:57:32 EST 2018
Note that the date command is expanded, which is what's happening in your script. However, if I quote the delimiter in the heredoc:
$ cat << "EOF"
> echo `date`
> EOF
You get the unexpanded output you want:
echo `date`
Similarly, escaping date would preserve the other variables you want to expand:
$ cat << EOF
> echo \$(date)
> EOF
Output:
echo $(date)

How to add threading to the bash script?

#!/bin/bash
cat input.txt | while read ips
do
cmd="$(snmpwalk -v2c -c abc#123 $ips sysUpTimeInstance)"
echo "$ips ---> $cmd"
echo "$ips $cmd" >> out_uptime.txt
done
How can i add threading to this bash script, i have around 80000 input and it takes lot of time?
Simple method. Assuming the order of the output is unimportant, and that snmpwalk's output is of no interest if it should fail, put a && at the end of each of the commands to background, except the last command which should have a & at the end:
#!/bin/bash
while read ips
do
cmd="$(nice snmpwalk -v2c -c abc#123 $ips sysUpTimeInstance)" &&
echo "$ips ---> $cmd" &&
echo "$ips $cmd" >> out_uptime.txt &
done < input.txt
Less simple. If snmpwalk can fail, and that output is also needed, lose the && and surround the code with curly braces,{}, followed by &. To redirect the appended output to include standard error use &>>:
#!/bin/bash
while read ips
do {
cmd="$(nice snmpwalk -v2c -c abc#123 $ips sysUpTimeInstance)"
echo "$ips ---> $cmd"
echo "$ips $cmd" &>> out_uptime.txt
} &
done < input.txt
The braces can contain more complex if ... then ... else ... fi statements, all of which would be backgrounded.
For those who don't have a complex snmpwalk command to test, here's a similar loop, which prints one through five but sleeps for random durations between echo commands:
for f in {1..5}; do
RANDOM=$f &&
sleep $((RANDOM/6000)) &&
echo $f &
done 2> /dev/null | cat
Output will be the same every time, (remove the RANDOM=$f && for varying output), and requires three seconds to run:
2
4
1
3
5
Compare that to code without the &&s and &:
for f in {1..5}; do
RANDOM=$f
sleep $((RANDOM/6000))
echo $f
done 2> /dev/null | cat
When run, the code requires seven seconds to run, with this output:
1
2
3
4
5
You can send tasks to the background by &. If you intend to wait for all of them to finish you can use the wait command:
process_to_background &
echo Processing ...
wait
echo Done
You can get the pid of the given task started in the background if you want to wait for one (or few) specific tasks.
important_process_to_background &
important_pid=$!
while i in {1..10}; do
less_important_process_to_background $i &
done
wait $important_pid
echo Important task finished
wait
echo All tasks finished
On note though: the background processes can mess up the output as they will run asynchronously. You might want to use a named pipe to collect the output from them.

BasH: run scripts in background

I am trying to run two scripts in the background. However I would like to have one script run first, wait for it to finish and run the next script recursively. Will this code snippet do as such:
for i in "${studyinstanceuids[#]}"
do
#let count="$count+1"
echo "$i" | ./cmd2&
sleep 5
if job1 is alive then sleep 5
echo "$i" | ./sendExamToRepo.sh&
wait
fi
for i in "${studyinstanceuids[#]}"; do
( echo "$i" | ./cmd2; echo "$1" | ./sendExamToRepo.sh )&
done
wait

Shell Scripting: execute echo statements with a time delay

Is there any way I could run several echo statements one after the other with a delay?
For example:
The first statement will be:
echo Hello1
after 1/2 second, run the Second echo statement:
echo Hello2
Likewise, is it possible to run several statements one after the other with a time delay without printing all echoes at once?
Perhaps you would like to use sleep <number of seconds>
Like sleep 60 to wait for a minute.
eg. run from commandline
$ echo 'hello1'; sleep 2; echo 'hello2'
or in a bash script file (myscript.sh)
#!/bin/bash
echo 'hello1'
sleep 2
echo 'hello2 after 2 seconds'
sleep 2
echo 'hello3 after 2 seconds'
echo Hello1
usleep 500000 # sleep 500,000 microseconds
echo Hello2
The usleep(1) command is part of the initscripts package on Fedora.
for i in `echo "hello1 hello2 hello3"`; do echo $i; sleep 2; done

Resources