问题
I am using cron to run a bash script periodically, and trying to use flock to prevent this script and the processes it creates from being run multiple times.
The entry in crontab to run it every minute is:
*/1 * * * * flock -n /tmp/mylockfile /home/user/myscript.sh arg1 arg2
The problem is, myscript.sh spawns multiple screen sessions in detached mode, it contains
for i in {1..3};
do
screen -d -m ./mysubscript.sh arg3
done
Running screen with "-d -m" as above starts screen in "detached" mode as forked process, but these processes do not inherit the lock from flock, so that every minute 3 new screen processes running mysubscript.sh show up.
If I use "-D -m" instead then only one screen process runs all the time until mysubscript.sh finishes, not three.
What I need is flock to only run myscript.sh if none of the the screen processes running mysubscript.sh are running.
How can this be achieved? Are there flags in screen or flock that can help to achieve this?
EDIT: If I change the line inside the for loop into running mysubscript.sh as a background process with:
./mysubscript.sh arg3 &
The locking behavior is exactly as I want, except that I do not have the separate screens anymore.
回答1:
Depending on your exact needs you can either run your subscript loop all consecutively or create individual screen sessions for each.
Multiple Screen Method
screens.sh
#!/bin/bash
if ! screen -ls | grep -q "screenSession"
then
for i in {1..3};
do
screen -S screenSession_${i} -d -m sh mysubscript.sh arg3 &
done
{ echo "waking up after 3 seconds"; sleep 3; } &
wait # wait for process to finish
exit # exit screen
else echo "Screen Currently Running"
fi
Sessions
62646.screenSession_1 (Detached)
62647.screenSession_2 (Detached)
62648.screenSession_3 (Detached)
This method will setup screens for each of iteration of your loop and execute the subscript. If cron happens to try and run the script while there are still active sockets then it will exit until next cron.
Single Screen Caller Method
screencaller.sh
#!/bin/bash
if ! screen -ls | grep -q "screenSession"
then screen -S screenSession -d -m sh screen.sh
else echo "Screen Currently Running"
fi
screen.sh
#!/bin/bash
for i in {1..3};
do
sh mysubscript.sh arg3
done
{ echo "waking up after 3 seconds"; sleep 3; } &
wait # wait for process to finish
exit # exit screen
Session
59916.screenSession (Detached)
This method uses a separate caller script then simply loops your subscript one after the other in the same screen session.
Either method would then be executed like so (eg. screens.sh, or screencaller.sh):
*/1 * * * * flock -n /tmp/mylockfile screens.sh arg1 arg2
Or if you wanted to run it manually from CLI just do:
$ sh screens.sh
If you wanted to enter the session you would just call screen -r screenSession
. A couple of other useful commands are screen -ls
and ps aux | grep screen
which shows the screens and processes that you are currently running.
来源:https://stackoverflow.com/questions/36364505/bash-cron-flock-screen