shell 按照什么顺序执行命令和流重定向?

shell 按照什么顺序执行命令和流重定向?

今天我尝试将stdout和重定向stderr到一个文件,然后遇到了以下情况:

<command> > file.txt 2>&1

这显然首先重定向stderrstdout,然后stdout将结果重定向到file.txt

但是,为什么顺序不是<command> 2>&1 > file.txt?人们会自然地将其理解为(假设从左到右执行)首先执行命令,然后stderr重定向到,然后将结果写入。但上面的只是重定向到屏幕。stdoutstdoutfile.txtstderr

shell 如何解释这两个命令?

答案1

当您运行 时,<command> 2>&1 > file.txtstderr 会被重定向2>&1到 stdout 当前所在的位置,即您的终端。此后,stdout 会被重定向到文件>,但 stderr 不会随之重定向,因此仍保留为终端输出。

首先通过<command> > file.txt 2>&1将 stdout 重定向到文件>,然后2>&1将 stderr 重定向到 stdout 的去向,即文件。

一开始这似乎有悖常理,但当你以这种方式考虑重定向,并记住它们是从左到右处理的,它就更有意义了。

答案2

如果你追溯一下,它可能会有意义。

一开始,stderr 和 stdout 指向同一个地方(通常是终端,我在这里称之为pts):

fd/0 -> pts
fd/1 -> pts
fd/2 -> pts

我指的是 stdin、stdout 和 stderr文件描述符这里的数字:它们分别是文件描述符 0、1 和 2。

现在,在第一组重定向中,我们有> file.txt2>&1

所以:

  1. > file.txtfd/1现在转到file.txt。当未指定任何内容时>1是隐含的文件描述符,因此这是1>file.txt

    fd/0 -> pts
    fd/1 -> file.txt
    fd/2 -> pts
    
  2. 2>&1fd/2现在去任何地方fd/1 现在去:

    fd/0 -> pts
    fd/1 -> file.txt
    fd/2 -> file.txt
    

另一方面,对于2>&1 > file.txt,顺序被逆转:

  1. 2>&1fd/2现在转到fd/1当前所在的位置,这意味着没有任何变化:

    fd/0 -> pts
    fd/1 -> pts
    fd/2 -> pts
    
  2. > file.txt:fd/1现在转到file.txt:

    fd/0 -> pts
    fd/1 -> file.txt
    fd/2 -> pts
    

重点是,重定向并不意味着重定向的文件描述符将遵循目标文件描述符的所有未来更改;它仅会采用当前的状态。

答案3

我认为 shell 首先会在左侧设置重定向,然后完全的在设置下一个重定向之前。

Linux 命令行William Shotts 说

首先我们将标准输出重定向到文件,然后将文件描述符 2(标准错误)重定向到文件描述符 1(标准输出)

这是有道理的,但是

请注意,重定向的顺序很重要。标准错误的重定向必须始终在标准输出重定向之后进行,否则它不起作用

但实际上,我们可以将 stderr 重定向到文件后,再将 stdout 重定向到 stderr,效果相同

$ uname -r 2>/dev/null 1>&2
$ 

因此,在 中command > file 2>&1,shell 将 stdout 发送到文件,然后将 stderr 发送到 stdout(正在发送到文件)。而在command 2>&1 > fileshell 中,首先将 stderr 重定向到 stdout(即在 stdout 通常所在的终端中显示它),然后将 stdout 重定向到文件。TLCL 误导性地指出我们必须首先重定向 stdout:因为我们可以先将 stderr 重定向到文件,然后将 stdout 发送到该文件。我们不能做的是将 stdout 重定向到 stderr 或反之亦然重定向到文件。另一个例子

$ strace uname -r 1>&2 2> /dev/null 
4.8.0-30-generic

我们可能认为这会将 stdout 处理到与 stderr 相同的位置,但事实并非如此,它首先将 stdout 重定向到 stderr(屏幕),然后仅重定向 stderr,就像我们反过来尝试时一样……

我希望这能带来一点光明......

答案4

顺序是从左到右。Bash 手册已经涵盖了您所问的问题。引自REDIRECTION手册中的一段:

   Redirections  are  processed  in  the
   order they appear, from left to right.

后面几行是:

   Note that the order of redirections is signifi‐
   cant.  For example, the command

          ls > dirlist 2>&1

   directs both standard output and standard error
   to the file dirlist, while the command

          ls 2>&1 > dirlist

   directs   only  the  standard  output  to  file
   dirlist, because the standard error was  dupli‐
   cated from the standard output before the stan‐
   dard output was redirected to dirlist.

需要注意的是,在运行任何命令之前,重定向首先被解析!参见https://askubuntu.com/a/728386/295286

相关内容