在哪里放置命令的 Bash shell 重定向?

Tim*_*ske 3 shell bash io-redirection file-descriptors

可能的重复:
重定向的顺序

除了独立exec >&2重定向当前 shell 的输入和输出之外,以下命令是否存在任何行为差异:

  1. echo -en "C\nB\nA\n" | sort 2>/dev/stdout >&2
  2. echo -en "C\nB\nA\n" 2>/dev/stdout >&2 | sort
  3. 2>/dev/stdout >&2 echo -en "C\nB\nA\n" | sort

如果上述命令等效,哪个是首选变体?

Gil*_*il' 5

首先,在一个简单的命令中(基本上是程序名称后跟一些参数),参数和重定向的相对位置并不重要。您甚至可以在命令名称之前进行重定向。以下都是等效的:

\n\n
foo --bar qux >out 2>err\nfoo >out --bar 2>err\n>out 2>err foo --bar qux\n
Run Code Online (Sandbox Code Playgroud)\n\n

(我不会列出所有可能性。)通常将重定向放在最后,因此如果不这样做,未来的读者可能会感到惊讶。然而,这只是风格问题。将输入重定向放在命令之前并在命令之后放置输出重定向有一些好处,特别是在管道中,因为它使读取顺序与处理顺序相同:

\n\n
<input.txt command1 | command2 | command3 >output.txt\n
Run Code Online (Sandbox Code Playgroud)\n\n

(对比command1 <input.txt | command2 \xe2\x80\xa6,将原点放在第一个处理步骤之后。)

\n\n

在复合命令中,您确实需要将重定向放在最后;例如,在以下代码片段中,您不能将重定向放在其他位置:

\n\n
while some_predicate; do some_action; done <in >out\n{ command1; command2; } <in >out\n
Run Code Online (Sandbox Code Playgroud)\n\n

当存在多个重定向时,如果它们重叠,即如果它们具有共同的文件描述符,则顺序很重要。请参阅重定向顺序

\n\n

在管道中,重定向适用于每个管道命令。在您的示例中,重定向sort仅适用于 (1) 命令,(2,3)echo仅命令。如上所述,(2)和(3)是等价的。

\n\n

在 (2) 和 (3) 中,输出最终echo位于重定向之前的相同位置。如果您编写了echo -en "C\\nB\\nA\\n" >&2 | sort,则管道左侧的命令不会向标准输出输出任何内容,因此sort会看到一个空的标准输入。

\n\n

您可以通过将命令块放在大括号中来重定向命令块的输入或输出:

\n\n
{ command1 | command2; } 2>error.log\n
Run Code Online (Sandbox Code Playgroud)\n\n

我假设您选择的重定向仅用于演示目的 \xe2\x80\x942>/dev/stdout >&2是一种复杂的编写方式2>&1(将标准错误(即 fd 2)重定向到标准输出(即 fd 1)当前所在的位置)。

\n