5

Greetings all. I'm setting up a cron job to execute a bash script, and I'm worried that the next one may start before the previous one ends. A little googling reveals that a popular way to address this is the flock command, used in the following manner:

flock -n lockfile myscript.sh
if [ $? -eq 1 ]; then
    echo "Previous script is still running!  Can't execute!"
fi

This works great. However, what do I do if I want to check the exit code of myscript.sh? Whatever exit code it returns will be overwritten by flock's, so I have no way of knowing if it executed successfully or not.

Paul Accisano
  • 1,416
  • 1
  • 14
  • 25

4 Answers4

6

It looks like you can use the alternate form of flock, flock <fd>, where <fd> is a file descriptor. If you put this into a subshell, and redirect that file descriptor to your lock file, then flock will wait until it can write to that file (or error out if it can't open it immediately and you've passed -n). You can then do everything in your subshell, including testing the return value of scripts you run:

(
  if flock -n 200
  then
    myscript.sh
    echo $?
  fi
) 200>lockfile
Brian Campbell
  • 322,767
  • 57
  • 360
  • 340
  • Or, if OP needs to use `$?` later, get rid of the subshell and do explicitly open/close, like `exec 200>lockfile; if ... fi; exec 200>&-`. – ephemient Dec 26 '09 at 22:10
2

According to the flock man page, flock has a -E or --exit-conflict-code flag you can use to set what the exit code of flock should be in the case a conflict occurs:

     -E, --conflict-exit-code number
              The exit status used when the -n option is in use, and the conflicting lock exists, or the -w option is in use, and the timeout is reached.  The default value is 1.  The number has to be in the range of 0 to 255.

The man page also states:

EXIT STATUS 
 
The command uses sysexits.h exit status values for everything, except when using either of the options -n or -w which report a failure to acquire the lock with a exit status given by the -E option, or 1 by default.  The exit status given by -E has to be in the range of 0 to 255.

When using the command variant, and executing the child worked, then the exit status is that of the child command.

So, in the case of the -n or -w flags while using the "command" variant, you can see both exit statuses.

Example:

$ flock --exclusive /tmp/flock.lock bash -c 'exit 42'; echo $?
42

$ flock --exclusive /tmp/flock.lock flock --exclusive --nonblock --conflict-exit-code 100 /tmp/flock.lock bash -c 'exit 42'; echo $?
100

In the first example, we see that we get back the exit status of the process we're running with flock. In the second example, we are creating contention for the lock. In that case, flock itself returns the status code we tell it (100). If you do not specify a value with the --conflict-exit-code flag, it will return 1 instead. However, I prefer setting less common values to prevent confusion from other processess/scripts which also might return a value of 1.

Keith
  • 36
  • 1
0

Perhaps something like this would work for you.

#!/bin/bash
RETVAL=0
lockfailed()
{
        echo "cannot flock"
        exit 1
}
(
        flock -w 2 42 || lockfailed
        false
        RETVAL=$?
        echo "original retval $RETVAL"
        exit $RETVAL
) 42>|/tmp/flocker
RETVAL=$?
echo "returned $RETVAL"
exit $RETVAL
kerolasa
  • 401
  • 2
  • 5
0
#!/bin/bash

if ! pgrep myscript.sh; then
  flock -n lockfile myscript.sh
fi

If I understand you right, you want to make sure 'myscript.sh' is not running before cron attempts to run your command again. Assuming that's right, we check to see if pgrep failed to find myscript.sh in the processes list and if so we run the flock command again.

SiegeX
  • 135,741
  • 24
  • 144
  • 154