为什么执行命令 ls -l file_doesnot_exists > /dev/null 2>&1 能够正常工作,而执行命令 ls -l 2>&1 file_doesnot_exists > /dev/null 则不能正常工作?

3

我想知道在shell命令中通常要先放哪个指令?例如,为什么这个命令:

ls -l file_doesnot_exists > /dev/null 2>&1

能运行,而这个命令:

ls -l 2>&1 file_doesnot_exists > /dev/null

不能。

2个回答

4

注意:

  • 这个问题被标记为linux,这意味着ls不是PowerShell自己的Get-ChildItem cmdlet的内置别名(仅适用于Windows),而是指标准的/bin/ls Unix实用程序。


  • PowerShell中,你的命令没有区别,因为重定向顺序不重要

    • 所有目标输出流始终保持其身份:任何流的重定向会影响同一命令中相同流的其他重定向。

    • 因此,两个命令都不按预期工作,产生没有输出的结果,因为2>&1将错误流(2)重定向到成功输出流(1),后者的输出最终会被丢弃,因为>/dev/null (>等同于1>), 包括被重定向的错误流输出。

  • 相比之下,在兼容POSIX的shell,例如Bash中,重定向的顺序很重要

    • ls -l 2>&1 file_doesnot_exists > /dev/null 按预期工作

      • 2>&1将stderr输出重定向到原始的stdout。
      • 稍后的stdout重定向(>等同于1>)对2>&1没有影响
      • 最终的效果是只有stderr行打印到stdout,而stdout行被(通过重定向至/dev/null)丢弃了。
    • 相比之下,ls -l file_doesnot_exists > /dev/null 2>&1 不起作用并产生没有输出

      • >/dev/null将stdout重定向到/dev/null,即有效地丢弃了stdout输出。

      • 因为2>&1出现在命令中较晚,所以1引用已经重定向的stdout,以至于stderr输出也被丢弃。

    • 有关更多信息,请参见此答案


1
假设这是在 PowerShell Core 中运行的(因为标签表明它是),那么可以肯定你混淆了 bash 命令和 PowerShell cmdlet。在 PowerShell 中,你必须注意终止非终止错误。
简单来说,ls -l 2>&1 file_doesnot_exists > /dev/null 不起作用的原因是,ls - 别名为 Get-ChildItem - 会产生一个终止错误,它会停止执行其余的命令,因为它缺少一个参数。这在 Try {...} catch {...} 语句中得到了证明,在该语句中,catch 块“捕获”终止错误。
try {
    ls -l
}
catch {
    "it no workie"
}

由于lsGet-ChildItem的别名,因此参数-L默认为-LiteralPath,它现在期望一个路径,并且在运行时出错,因为没有提供路径。

1
我的错,我以为bash命令和Powershell是一样的。我在MacOS上运行这些命令,所以这是一个bash命令。 - HamzaDevXX
2
@HamzaDevXX,不是,但这种情况经常发生。编辑:请看Mklement的答案。 - Abraham Zinala

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接