A recommended way to acquire a lock in Bash is to open the lock file for a group command, and call flock on the open descriptor before doing anything dangerous:
{
echo waiting
flock -x 9
echo in
sleep 10
echo done
} 9> /tmp/lock
Try it in two independent terminals. The second command will run only as the first finishes.
However, one should never have to pick an arbitrary file descriptor (9 in this case). Fortunately, you can get Bash to choose an available descriptor, using {var} in place of the literal descriptor number:
unset lfd
{
echo waiting
flock -x $lfd
echo in
sleep 10
echo done
} {lfd}> /tmp/lock
Problem solved!
No, wait. The descriptor doesn't get closed at the end of the group command, so your second invocation will hang indefinitely. Once the first terminal has finished, if you manually close the descriptor, the second proceeds:
exec {lfd}>&-
Looks like you have to do things more explicitly (and the group command is no longer useful):
echo waiting
unset lfd
exec {lfd}> /tmp/lock
flock -x $lfd
echo in
sleep 10
echo done
exec {lfd}>&-
This is inconvenient if you want to break or continue out of an enclosing loop:
for i in $(seq 1 10)
do
{
echo waiting
flock -x 9
echo in
sleep 5
if something_went_wrong ; then continue ; fi
sleep 5
echo done
} 9> /tmp/lock
done
Is this a bug, a feature, or a mistake on my part? (Bash version 4.4.20(1)-release.)

No comments:
Post a Comment