exi*_*tus 27 io-redirection stdout stderr
我从空目录开始。
$ touch aFile
$ ls
aFile
Run Code Online (Sandbox Code Playgroud)
然后我有ls
两个参数,其中一个不在此目录中。我将两个输出流都重定向到一个名为output
. 我使用>>
是为了避免同时写入。
$ ls aFile not_exist >>output 2>>output
$ cat output
ls: cannot access 'not_exist': No such file or directory
aFile
Run Code Online (Sandbox Code Playgroud)
这似乎有效。这种方法有什么危险吗?
Kus*_*nda 22
当你这样做时会发生什么
some_command >>file 2>>file
Run Code Online (Sandbox Code Playgroud)
是file
将打开以追加两次。在 POSIX 文件系统上这样做是安全的。无论数据是通过标准输出流还是标准错误流,在打开文件进行追加时发生的任何写入都将发生在文件末尾。
这依赖于对底层文件系统中的原子追加写入操作的支持。某些文件系统,例如 NFS,不支持原子追加。例如,参见StackOverflow 上的问题“在 UNIX 中文件追加是原子的吗?”。
使用
some_command >>file 2>&1
Run Code Online (Sandbox Code Playgroud)
即使在 NFS 上也能工作。
但是,使用
some_command >file 2>file
Run Code Online (Sandbox Code Playgroud)
不安全,因为 shell 会截断输出文件(两次),并且在任一流上发生的任何写入都将覆盖另一个流已经写入的数据。
例子:
some_command >>file 2>>file
Run Code Online (Sandbox Code Playgroud)
所述hello
字符串被首先写入(与终止行),然后将串abc
跟着一个新行从标准误差写入,覆盖hell
。结果是abc
带有换行符的字符串,后跟第一个echo
输出的剩余部分、ano
和换行符。
交换两个echo
围绕伤口仅hello
在输出文件中产生,因为该字符串最后写入并且比abc
字符串长。重定向发生的顺序无关紧要。
使用更惯用的词会更好更安全
some_command >file 2>&1
Run Code Online (Sandbox Code Playgroud)
mos*_*svy 22
不,它不仅与标准一样安全>>bar 2>&1
。
当你写作
foo >>bar 2>>bar
Run Code Online (Sandbox Code Playgroud)
您使用bar
两次打开文件O_APPEND
,创建两个完全独立的文件对象[1],每个文件对象都有自己的状态(指针、打开模式等)。
这与2>&1
仅调用dup(2)
系统调用非常不同,并且使 stderr 和 stdout 为同一文件对象具有可互换的别名。
现在,有一个问题:
O_APPEND
如果多个进程同时将数据附加到一个文件,则可能会导致 NFS 文件系统上的文件损坏。这是因为 NFS 不支持附加到文件,所以客户端内核必须模拟它,这在没有竞争条件的情况下是无法完成的。
通常你可以对文件的概率计算类似bar
中foo >>bar 2>&1
从两个不同的地方是相当低的,同时被写入。但是,>>bar 2>>bar
你只是将它增加了十几个数量级,没有任何理由。
[1] POSIX 术语中的“打开文件描述”。