当设置了“noclobber”选项时,“/dev/null”与其他文件的处理方式是否不同?

Ric*_*mas 6 bash

作为一个实验,我尝试运行set -o noclobber然后运行echo foo > /dev/null​​. 我能够做到这一点;没有出现错误:

bash-3.2$ set -o noclobber
bash-3.2$ echo "foo" > /dev/null
bash-3.2$ echo "bar" > /dev/null
bash-3.2$ echo "baz" > /dev/null
Run Code Online (Sandbox Code Playgroud)

但是,当我对之前创建的文件尝试相同的操作时,我看到了预期的错误:

bash-3.2$ touch bar.txt
bash-3.2$ echo "bar" > bar.txt
bash: bar.txt: cannot overwrite existing file
Run Code Online (Sandbox Code Playgroud)

noclobber该文件的处理方式与其他文件的处理方式是否/dev/null不同?

注意:我理解为什么它可能会这样做(即因为它的性质/dev/null和目的),但我在这里没有看到任何有关此效果的文档。我想这可能是一个未记录的功能,或者(可能更有可能)我只是错过了文档?

mur*_*uru 12

第 3.6.2 节重定向输出说:

\n
\n

如果重定向运算符为 \xe2\x80\x98 >\xe2\x80\x99,并且已启用noclobber内置选项set,则如果名称由单词扩展产生的文件存在且是常规文件,则重定向将失败。

\n
\n

/dev/null和家人并不是普通的档案。它们是“字符特殊文件”:

\n
$ [ -c /dev/null ] ; echo $?\n0\n$ [ -f /dev/null ] ; echo $?\n1\n
Run Code Online (Sandbox Code Playgroud)\n

这同样适用于其他非常规文件,例如 FIFO 管道:

\n
$ mkfifo foo; set -o noclobber\n$ echo > .bashrc\nbash: .bashrc: cannot overwrite existing file\n$ cat foo & echo a > foo\n[1] 18857\na\n
Run Code Online (Sandbox Code Playgroud)\n

(大概还有套接字、块设备等)

\n

  • 实际上,shell 需要首先检查文件类型的事实意味着存在 TOCTOU 竞争,并且在攻击者将 /dev/null 的符号链接替换为右侧另一个文件的符号链接时, noclobber 并不安全例如时刻。 (6认同)
  • 我想 shell 可以通过首先打开文件,然后检查类型,如果它得到的是常规文件则退出,而不破坏文件来解决这个问题。如果找不到文件,它会再次尝试使用“O_CREAT|O_EXCL”来创建它。如果文件是在两者之间创建的,则后一个调用将意外失败,但它至少是无害的(并且 shell 可以从头开始重试以查看创建的文件是否是常规文件。) (2认同)
  • @StéphaneChazelas:恕我直言,shell 首先不应该用于实现安全边界,但用户可能不会关心我的想法。 (2认同)
  • 就我个人而言,我不认为“noclobber”是一个安全功能,而是一个护栏。当然,如果我真的想的话,我可以跳过护栏,或者有人可以把我推过它,但这些不是护栏旨在防范的情况。 (2认同)
  • @ilkkachu:如果您这样做是出于安全原因,而不是像 muru 所说的那样只是作为“护栏”,另一种方法是“open(O_CREAT|O_WRONLY)”(*没有* O_TRUNC 或 O_APPEND)。然后,如果“fstat”告诉您这是一个常规文件,请退出并“关闭”。您可能会也可能不会先“stat”作为提前退出,以避免更新时间戳。在相关情况下,如果您想在某些检查后截断常规文件,您可以在不截断的情况下打开,然后“ftruncate(fd, 0)”(POSIX.2001,https://man7.org/linux/man-pages /man2/ftruncate.2.html)。你的方法也有效,但必须处理比赛。 (2认同)