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?
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:
ps
is formatted to include pid and parent pid information
$$
)grep
executions1
to 0
since also the current process was excluded from the ps
results