Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
604 views
in Technique[技术] by (71.8m points)

linux - bash cron flock screen

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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

1.4m articles

1.4m replys

5 comments

57.0k users

...