3

I've tried this solution to prevent duplicate cronjob from running.

30,31 12 * * * /usr/bin/flock -n /tmp/my.lockfile ~/Desktop/test.sh >> ~/Desktop/test.log 2>&1

and script test.sh has

#!/bin/bash

for i in {1..40};do
    echo "hello$i"
    sleep 2
done

Script test.sh successfully prevented from running at 12:31 but it stops and I want to resume it. How can I make it only suspend, not stopped and resume back? Is it possible?

d a i s y
  • 5,551

1 Answers1

2

You can add a test, in the beginning of the script, to check whether there are another early started instances of the script and while this is true the current instance will sleep. Something like that:

while ps aux | grep -v 'grep' | grep "$0" | sed -e "/$$/p" -e "/$$/,$ d" | grep -vq "$$"
do sleep 1
done

Where:

  • the variable $0 contains the script name (and execution path);

  • the variable $$ contains the PID of the current running instance of the script;

  • ps aux - output the current processes;

  • grep -v 'grep' - preserve the lines that contains grep within the output of the previous command;

  • grep "$0" - output only the lines that are related to the current script name;

  • sed -e "/$$/p" -e "/$$/,$ d" - remove the newer instances of the script; remove all lines after the line that contains the PID of the current instance;

  • grep -vq "$$" - this is the actual test -q that will return 0 (true - there is at least one older instance of the script) or 1 (false - apparently this is the newest existing instance of the script) when the line with PID of the current instance is removed -v.

Here is a complete example:

#!/bin/bash

while ps aux | grep -v 'grep' | grep "$0" | sed -e "/$$/p" -e "/$$/,$ d" | grep -vq "$$"
do
        sleep 1
        echo -n '.'
done

date +"%T"

for i in {1..5};do
    echo "hello$i"
    sleep 2
done

Here is the test I've made:

enter image description here

In addition you can create a launcher script that will execute your actual script in the above manner.

$ cat ~/Desktop/test-cron-launcher.sh 
#!/bin/bash

LAUNCH_TIME="$(date +"%T")"

while ps aux | grep -v 'grep' | grep "$0" | sed -e "/$$/p" -e "/$$/,$ d" | grep -vq "$$"
do sleep 1
done

echo "Job from $LAUNCH_TIME begin at $(date +"%T")"

. "$HOME/Desktop/test.sh"
$ cat ~/Desktop/test.sh 
#!/bin/bash
for i in {1..40};do
    echo "hello$i"
    sleep 2
done
$ crontab -l | grep 'test'
30,31 12 * * * "$HOME/Desktop/test-cron-launcher.sh" >> "$HOME/Desktop/test.log" 2>&1

Read also:

pa4080
  • 30,621