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

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

可能的重复:
重定向顺序

除了独立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

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

答案1

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

foo --bar qux >out 2>err
foo >out --bar 2>err
>out 2>err foo --bar qux

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

<input.txt command1 | command2 | command3 >output.txt

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

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

while some_predicate; do some_action; done <in >out
{ command1; command2; } <in >out

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

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

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

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

{ command1 | command2; } 2>error.log

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

答案2

1 与 2 和 3 不同。2 和 3 相同。

在版本 1 中,C\nB\nA\n被发送到sort.sort的 FD 2 从其原始目的地 ( STDERR) 映射到STDOUT,然后无论如何都会到达的 FD 1又STDOUT被发送到 ...sortSTDOUT(相当无意义)。

在版本 2 和 3 中,echo的 FD 2 从其原始目的地 ( STDERR) 映射到STDOUT,然后将无论如何都会到达的 FD 1STDOUT发送到echo' STDOUT

从功能上讲,如果其中一个命令将某些内容发送到 ,这些命令只会产生不同的输出STDERR

在版本 1 中,如果echo向 FD 2 输出某些内容,它将转到STDERR,但在版本 2 和 3 中,它将转到STDOUT(因此也通过管道传输到sort)。另外,在版本 1 中,如果sort向 FD 2 发送某些内容,它将转到STDOUT,而在版本 2 和 3 中,该输出将转到STDERR

就“首选变体”而言,您确实应该使用更像这样的东西(假设您想要echo's STDERRgo to sort):

echo -en "C\nB\nA\n" 2>&1 | sort

这是可行的,因为默认情况下 FD 1 已经进入STDOUT,只需让 FD 2 将文件描述复制到其描述符即可。

相关内容