2013年8月19日,Randal L. Schwartz发布了该 Shell脚本,该脚本旨在确保在Linux上“该脚本只有一个实例在运行,而没有竞争条件或无需清除锁定文件”:
#!/bin/sh
# randal_l_schwartz_001.sh
(
if ! flock -n -x 0
then
echo "$$ cannot get flock"
exit 0
fi
echo "$$ start"
sleep 10 # for testing. put the real task here
echo "$$ end"
) < $0
它似乎按广告宣传工作:
$ ./randal_l_schwartz_001.sh & ./randal_l_schwartz_001.sh
[1] 11863
11863 start
11864 cannot get flock
$ 11863 end
[1]+ Done ./randal_l_schwartz_001.sh
$
这是我的理解:
- 脚本将
<
自身内容的副本(即从$0
)重定向()到0
子shell 的STDIN(即文件描述符)。 - 在子Shell中,脚本尝试获取
flock -n -x
文件描述符上的非阻塞排他锁()0
。- 如果该尝试失败,则子外壳程序退出(主脚本也将退出,因为没有其他操作可做)。
- 如果尝试成功,则子外壳程序将运行所需的任务。
这是我的问题:
- 为什么脚本需要将其自身内容的副本而不是其他文件的内容重定向到子shell继承的文件描述符?(我尝试从另一个文件重定向并按上述方式重新运行,并且执行顺序发生了变化:非后台任务在后台任务之前获得了锁。因此,也许使用文件本身的内容可以避免竞争;但是如何?)
- 无论如何,为什么脚本需要将文件内容的副本重定向到子shell继承的文件描述符?
- 为什么
0
在一个shell中对文件描述符进行独占锁定会阻止在不同shell中运行的同一脚本的副本获得对文件描述符的独占锁定0
?不要炮弹都有自己的标准文件描述符(的单独副本0
,1
和2
,即STDIN,STDOUT和STDERR)?