【问题标题】:Whether to redirect stderr to stdout OR redirect both to the same file?是否将 stderr 重定向到 stdout 或将两者都重定向到同一个文件?
【发布时间】:2018-12-22 04:28:53
【问题描述】:

哪个更好?

  • cmd >>file 2>&1
  • cmd 1>>file 2>>file

有区别吗?


我知道选择第一个的两个原因:它也适用于 > 而不是 >>。它更受欢迎,因此知道 shell 脚本的人会立即排除它。

但是,我仍然觉得第二个可读性更好,并且无需了解 [n]>&[n] 语法即可工作,恕我直言,这有点令人困惑。

【问题讨论】:

  • 是否有两个打开的文件描述(带有它们自己的,大多是无意义的文件偏移量)算作差异?
  • 您通常会将第二种形式视为cmd 1>>outfile 2>>errfile(这是使用两个描述符的唯一好处)
  • 在现代 shell 中,您只需使用 &>> (bash) 或 >>& (tcsh)。
  • 或者对于 bash,如果同时重定向两者,只需 &>file
  • @DavisHerring 如果这是一个实际问题,(速度/最大打开文件/...)应该考虑在内。但我更想知道拥有两个文件描述符是否会产生真正的区别,比如混淆输出序列

标签: shell


【解决方案1】:

有什么区别?

让我们来看看每个命令的含义。我假设POSIX shell specification 适用,因为该问题没有询问任何更具体的内容。

第一个命令是cmd >>file 2>&1。这在设置指定的重定向后运行cmd

重定向>>file 打开带有O_APPEND 的命名文件。正如open 的规范中所解释的,这将创建一个新的Open File Description,其中特别包含当前文件偏移量,并安排File Descriptor 1 引用该描述。 O_APPEND的意思是“每次写入前,文件偏移量应设置为文件末尾”。

重定向2>&1 表示文件描述符 2“应作为文件描述符 1 的副本”。该规范有点含糊,但我认为唯一合理的解释(以及 shell 实际执行的操作)就是它表示调用dup2(1, 2),“将导致文件描述符 [2] 引用与文件描述符 [1] 相同的打开文件描述”。至关重要的是,我们得到另一个文件 descriptor,但继续使用同一个文件 description,这意味着它们都具有相同的文件偏移量。

第二个命令是cmd 1>>file 2>>file。根据上面引用的规范,这会为 file 创建两个单独的文件描述,每个都有自己的偏移量。

现在,如果 cmd 对文件描述符 1 和 2 所做的唯一事情是调用 write,那么这两种情况等效,因为每次调用 write 都会自动在执行写入之前更新偏移量以指向文件的末尾,因此第二个命令中存在两个单独的偏移量不会有任何明显的影响。

但是,如果cmd 执行一些其他操作,例如lseek,那么这两种情况不等价,因为这将表明第一个命令有一个共享偏移量,而第二个命令有两个独立的偏移量。

此外,上面假设O_APPEND 的POSIX 指定语义。但真正的计算机系统并不总是实现这一点。例如,NFS does not have atomic append。如果没有原子附加,即使只执行了write,第二个命令的行为也可能不同(很可能会破坏输出)。

哪个更好?

由于两个命令的含义不同,哪个更好大概取决于哪个含义更接近您的意图。我推测,几乎在所有情况下,其目的都是将来自cmd 的标准输出和标准错误都附加到file,而这些描述符假定只有write。这正是第一个命令(cmd >>file 2>&1)的含义,因此是更好的选择。

虽然第二个命令确实使用了较少的 shell 功能,因此对于某些人来说可能更容易理解,但对于那些 确实 更熟悉重定向语法的人来说,这可能看起来很奇怪,甚至可能在某些情况下,行为与预期不同。因此我建议不要这样做,如果我在我维护的某些代码中发现它,我会倾向于将其更改为第一种形式。

当然,如果您真的想要单独的文件描述,因此需要单独的文件偏移量,那么第二个命令是有意义的,只要您在附近放置注释来解释异常构造的基本原理。

【讨论】:

    猜你喜欢
    • 2014-07-22
    • 1970-01-01
    • 1970-01-01
    • 2011-12-28
    • 1970-01-01
    • 2011-11-23
    • 2023-02-14
    • 2015-06-21
    • 2013-02-15
    相关资源
    最近更新 更多