在系统调用open()
,如果我打开与O_CREAT | O_EXCL
,系统调用确保该文件将被创建,如果它不存在。原子性由系统调用保证。有没有类似的方式从bash脚本以原子方式创建文件?原子创建文件,如果不存在bash脚本
更新: 我发现了两个不同的原子的方式
- 使用设置-o noclobber选项。然后你可以自动使用>运算符。
- 只需使用mkdir即可。 Mkdir是原子的
在系统调用open()
,如果我打开与O_CREAT | O_EXCL
,系统调用确保该文件将被创建,如果它不存在。原子性由系统调用保证。有没有类似的方式从bash脚本以原子方式创建文件?原子创建文件,如果不存在bash脚本
更新: 我发现了两个不同的原子的方式
100%纯bash的解决方案:
set -o noclobber
{ > file ; } &> /dev/null
此命令创建一个名为file
文件,如果有一个名为file
不存在的文件。如果有一个名为file
的文件,则不做任何操作(但返回一个非零返回码)。
优点WRT的touch
命令:
file
已经存在失败或者file
couldn”不被创造;如果file
不存在并且已创建,则成功。缺点:
noclobber
选项(但没关系,在脚本中,如果你小心重定向,或取消其以后)。我想这个解决方案真的是open
系统调用与O_CREAT | O_EXCL
的bash相对应。
+1 - 短而干净。 –
“>文件”保证是原子? –
'(set -o noclobber;> file)&>/dev/null'也一样,但不会影响当前shell中的'noclobber'选项。 –
touch
是您正在查找的命令。它会更新所提供文件的时间戳,如果该文件存在,或者创建它,如果没有。
除非文件已经存在,否则不会失败,正如O_EXCL所做的那样。 –
我没有看过触摸源,但它可能不是原子的。 Otoh,如果文件存在,它会改变访问和修改时间。 –
触摸不是原子 – Jimm
要明确一点,确保文件只有在不存在时才会被创建,这与原子性不同。这个操作是原子的,当且仅当两个或更多独立的线程同时尝试做同样的事情时,正好一个会成功,其他所有的线程都会失败。
我所知道的在shell脚本原子创建一个文件的最佳方法遵循此模式(和它的不完美):
尤其touch
不是原子,因为它会创建一个文件,如果它不存在,或者简单地更新时间戳。你可以用不同的时间戳来玩游戏,但是阅读和解析一个时间戳,看看你是否赢得了比赛比上面更难。 mkdir
可以是原子的,但是你必须检查返回代码,否则,你只能说“是的,该目录是创建的,但我不知道哪个线程获胜”。如果您使用的是不支持硬链接的文件系统,那么您可能不得不选择不太理想的解决方案。
您可以在随机生成的名称下创建它,然后使用所需的名称重命名(mv -n random desired
)它到位。如果文件已经存在,重命名将失败。
像这样:
#!/bin/bash
touch randomFileName
mv -n randomFileName lockFile
if [ -e randomFileName ] ; then
echo "Failed to acquired lock"
else
echo "Acquired lock"
fi
我的“mv”不是原子的。 它首先使用“stat”来测试目标文件是否存在,如果不存在,则使用“rename”。但是“重命名”只会覆盖目标。因此,在“统计”和“重命名”调用之间有一个很小的时间框架,其中用目标名称创建的文件将被覆盖。 – SIGSEGV
啊,有趣。 'mv'根本没有帮助,那么,对不起。 –
下面是一个使用mv -n
招bash函数:
function mkatomic() {
f="$(mktemp)"
mv -n "$f" "$1"
if [ -e "$f" ]; then
rm "$f"
echo "ERROR: file exists:" "$1" >&2
return 1
fi
}
例子:
$ mkatomic foo
$ wc -c foo
0 foo
$ mkatomic foo
ERROR: file exists: foo
_The系统调用确保如果它不exist_哼文件才会被创建。如果文件不存在,它将被创建。如果存在,系统调用将失败。 – pbhd
您可以尝试'mktemp'来创建一个文件,然后尝试将其“mv”到所需的名称。 –