Pass multiple commands to flock
Invoke a shell explicitly.
flock -x -w 5 ~/counter.txt sh -c 'COUNTER=$(cat counter.txt); echo $((COUNTER + 1)) > ~/counter.txt'
Note that any variable that you change is local to that shell instance. For example, the COUNTER
variable will not be updated in the calling script: you'll have to read it back from the file (but it may have changed in the meantime), or as the output of the command:
new_counter=$(flock -x -w 5 ~/counter.txt sh -c 'COUNTER=$(cat counter.txt); echo $((COUNTER + 1)) | tee ~/counter.txt')
Or you can flock a file descriptor
exec {counterfd}<~/counter.txt
flock -x -w 5 "$counterfd"
COUNTER=$(cat ~/counter.txt)
COUNTER=$(( COUNTER +1 ))
echo "$COUNTER" >~/counter.txt
exec {counterfd}<&-
This also has the benefit of allowing you to use the counter variable directly, unlike subshell based approaches.
The flock
tool is a little tricky to use and the man page is pretty short. The man page provides three ways to use the tool:
flock [options] <file|directory> <command> [command args]
flock [options] <file|directory> -c <command>
flock [options] <file descriptor number>
The way this question is worded I would definitely use the third form of flock
. If you go further down in the man page for flock
there are some examples which show the exact syntax for using the third form:
#!/bin/bash
(
flock -n 9 || exit 1
echo "commands executed under lock..."
echo "go here..."
) 9>/tmp/mylockfile
I added the #!/bin/bash
.
I have successfully used this form of flock
.