Reputation: 263
I am trying to lock a file using bash, and I have managed to do so, but I am not sure if I am doing it the right way.
The following piece of code should try to write into the lock.log
file and if it fails it should exit with exit status -1. If it can lock the file, then it should print the order number, unlock the file, and exit.
#!/bin/bash
function myfunc {
(
flock -e -n 200 || { echo "$1 - can't reach"; exit -1; }
echo $1 >> $2 #critical
sleep 2
flock -u 200
) 200>$2 #critical
echo "$1 -> end."
exit 0
}
lock="lock.log"
for ((i=0; i < 10; i++)); do
myfunc $i $lock &
done
exit 0
I could not understand why it would print on the standard output and the 2 lines that are tagged as critical are not quite clear to me, so I kindly ask for some explanation and maybe for a better example.
There may be some similar questions, but none with the basic things that I am asking - the usage of flock
Thank you
Upvotes: 1
Views: 925
Reputation: 46853
Let's start with the 200>"$2"
part:
When myfunc
is called Bash sees this:
(
... stuff irrelevant for now ...
) 200>"$2"
so it opens file descriptor number 200 and will redirect it to the file obtained by expansion of $2
. In your case, it's exactly like:
(
... stuff irrelevant for now ...
) 200>lock.log
By the way, file lock.log
is at this point opened and truncated (i.e., its content, if any, is cleared).
To see this, try the following:
( ls /dev/fd ) 200>lock.log
You'll see that there's a “file” called 200
in there (at this point, try it with a lock.log
file that has some content, and you'll see that after that its content disappeared) but compare with
ls /dev/fd
where you very likely only see 0
, 1
, 2
, 3
. For fun, try:
( ls /dev/fd >&200 ) 200>lock.log
This time nothing is shown on your terminal screen, but you'll see that the content of ls
is in the file lock.log
(with its previous content, if any, deleted). That's because with >&200
we redirected the standard output of ls
to the file descriptor 200
which is /dev/fd/200
, and this is then redirected to the file lock.log
.
I guess this explains one of the critical lines.
Now what happens inside the subshell? I'm no flock
expert, so bear with me.
With the argument 200
, you're telling flock
to use the file descriptor 200
(i.e., the “file” /dev/fd/200
) as a lock file. When you call flock 200
, flock
tries to get a hold on the file. If it can, all is good, it keeps the grasp on it, otherwise it either fails (if given the -n
option, which is your case) or it waits until someone else let the file go.
In case of failure, you're outputting the can't reach message to standard output and exit the subshell, and then you're executing the remaining part of the function (namely, the message end). Now, in case of success you're echo
ing the first argument passed to the function (here a number) and you're redirecting it to file lock.log
. Does that explain the second critical line?
At the end of this script, you'll see that the file lock.log
is empty. That's because the first call to myfunc succeeds, but all subsequent calls will truncate the file lock.log
(rings a bell with you?). If you want to see some content inside lock.log
, either call your function only once (so that no subsequent calls truncate the file), or open the file in append mode:
(
... the flock stuff ...
) 200>>"$2" # notice the >> instead of >
Like so you'll see the first lock that succeeded (not necessarily the number 0
, as there are race conditions).
Upvotes: 2