问题
I have a shell script executed by cron and I want to control that it's not already running. This is my control test:
set -A processes
ps -elf | grep -v grep | grep -E "/bin/ksh.+scriptName" | while read line ;do processes[${#processes[@]}]="$line";done
if [ ${#processes[@]} -gt 1 ]; then
for i in {0..$((${#processes[@]}-1))}; do echo "${processes[$i]}"; done
exit 1
fi
The problem is that this control returns sometimes 2 processes (of itself):
F S UID PID PPID C PRI NI ADDR SZ WCHAN STIME TTY TIME CMD
0 S user 12486 12485 0 85 0 - 2469 - 15:30 ? 00:00:00 /bin/ksh /path/scriptName ARG1
1 D user 12503 12486 0 85 0 - 2469 get_wr 15:30 ? 00:00:00 /bin/ksh /path/scriptName ARG1
I do not understand why it happens sometimes...How to resolve this problem? How to control a script is not already running (without "flag"/semaphore file)? Thanks for your help!
回答1:
Two options:
- Allow the job to start, but have scriptName script check if it is already running and kill itself.
- Switch to a more sophisticated job scheduler such as http://nerds.airbnb.com/introducing-chronos/
回答2:
Using pipes can spawn subprocesses, which show up in the process table. Limit the "ps" output and it becomes easier to parse:
ps -eo pid,ppid,args | grep -vw $$ | grep -qE "[0-9]+ /bin/ksh $0" && echo "ALREADY RUNNING"
This removes anything from the list that has the current PID ($$) as its PID or Parent PID, and then matches the scriptname as a pattern. You really don't even need the "[0-9]+" in the pattern, since the first grep excludes all of your child processes (otherwise the "grep" itself would match).
来源:https://stackoverflow.com/questions/25254017/how-to-control-a-script-is-not-already-running