Search code examples
cronksh

Detect multiple executions of same ksh


I am trying to detect if a ksh script is already executing in order to prevent a second instance to be executed.

The script is invoked every minute by user cronjob:

* * * * * /home/user/job.ksh TESTACTION &>/dev/null

I added a guard at the beginning of the script:

#!/usr/bin/ksh

LOGDIR="/home/user"

processes=$(/bin/ps ux | /bin/grep -i "job.ksh TESTACTION" | /bin/grep -v grep | /bin/grep -c "\/usr\/bin\/ksh")
if (( $processes > 1 )); then
    datetime=$(/bin/date +'%Y.%m.%d %H:%M:%S')
    /bin/echo -e "${datetime} - skipped execution for other ${processes} active process" >> "${LOGDIR}/multiple_ksh_check.log"
    exit 0
fi

With my surprise the if condition is satisfied often but not always, as I can see from the log file.

Consider that for testing purposes I reproduced the problem with this code snippet, which means that the script lasts few milliseconds, no way that it lasts for a minute, to collide with the next cronjob call.

What am I missing? What can I try?


Solution

  • The point that I was missing was that a shell can spawn subshells in other processes, that's why ps was finding more lines than expected.

    With some help by @markp and this answer I rewrote the condition like this

    processes=$(/bin/ps x -o pid,ppid,args | /bin/grep -vw $$ | /bin/grep -i "job.ksh TESTACTION" | /bin/grep -c "\/usr\/bin\/ksh")
    if (( $processes > 0 )); then
         exit 0
    fi
    

    here the main points:

    • The output of ps is formatted to include pid and parent pid information
      • I filter out the lines containing the current process'pid (contained into the special var $$)
      • this way I do not need to filter out grep executions
      • I had to change the check from 1 to 0 since also the current process was excluded from the ps results