How do I make sure my bash script isn't already running?

后端 未结 13 836
無奈伤痛
無奈伤痛 2020-12-31 05:56

I have a bash script I want to run every 5 minutes from cron... but there\'s a chance the previous run of the script isn\'t done yet... in this case, i want the new run to j

相关标签:
13条回答
  • 2020-12-31 06:18

    As a one-liner and if you do not want to use a lockfile (e.g. b/c/ of a read only filesystem, etc)

    test "$(pidof -x $(basename $0))" != $$ && exit
    

    It checks that the full list of PID that bear the name of your script is equal to the current PID. The "-x" also checks for the name of shell scripts.

    Bash makes it even shorter and faster:

    [[ "$(pidof -x $(basename $0))" != $$ ]] && exit
    
    0 讨论(0)
  • 2020-12-31 06:23

    You can always just:

     if ps -e -o cmd | grep scriptname > /dev/null; then 
         exit
     fi
    

    But I like the lockfile myself, so I wouldn't do this without the lock file as well.

    0 讨论(0)
  • 2020-12-31 06:24

    I was trying to solve this problem today and I came up with the below:

    COMMAND_LINE="$0 $*"
    JOBS=$(SUBSHELL_PID=$BASHPID; ps axo pid,command | grep "${COMMAND_LINE}" | grep -v $$ | g    rep -v ${SUBSHELL_PID} | grep -v grep)
    if [[ -z "${JOBS}" ]]
    then
        # not already running
    else
        # already running
    fi
    

    This relies on $BASHPID which contains the PID inside a subshell ($$ in the subshell is the parent pid). However, this relies on Bash v4 and I needed to run this on OSX which has Bash v3.2.48. I ultimately came up with another solution and it is cleaner:

    JOBS=$(sh -c "ps axo pid,command | grep \"${COMMAND_LINE}\" | grep -v grep | grep -v $$")
    
    0 讨论(0)
  • 2020-12-31 06:25

    Never use a lock file always use a lock directory. In your specific case, it's not so important because the start of the script is scheduled in 5min intervals. But if you ever reuse this code for a webserver cgi-script you are toast.

    if mkdir /tmp/my_lock_dir 2>/dev/null
    then
       echo "running now the script"
       sleep 10
       rmdir /tmp/my_lock_dir
    fi
    

    This has a problem if you have a stale lock, means the lock is there but no associated process. Your cron will never run.

    Why use a directory? Because mkdir is an atomic operation. Only one process at a time can create a directory, all other processes get an error. This even works across shared filesystems and probably even between different OS types.

    0 讨论(0)
  • 2020-12-31 06:31

    Store your pid in mylockFile. When you need to check, look up ps for the process with the pid you read from file. If it exists, your script is running.

    0 讨论(0)
  • 2020-12-31 06:32
    # Use a lockfile containing the pid of the running process
    # If script crashes and leaves lockfile around, it will have a different pid so
    # will not prevent script running again.
    # 
    lf=/tmp/pidLockFile
    # create empty lock file if none exists
    cat /dev/null >> $lf
    read lastPID < $lf
    # if lastPID is not null and a process with that pid exists , exit
    [ ! -z "$lastPID" -a -d /proc/$lastPID ] && exit
    echo not running
    # save my pid in the lock file
    echo $$ > $lf
    # sleep just to make testing easier
    sleep 5
    

    There is at least one race condition in this script. Don't use it for a life support system, lol. But it should work fine for your example, because your environment doesn't start two scripts simultaneously. There are lots of ways to use more atomic locks, but they generally depend on having a particular thing optionally installed, or work differently on NFS, etc...

    0 讨论(0)
提交回复
热议问题