如何理解输出重定向的顺序?

所以我正在努力学习如何将标准输出和标准错误传递到各个领域。

假设我只有here.txt的文件夹。

所以,如果我这样做

 ls here.txt not-here.txt 1>out 2>&1 

由于here.txt存在,我将有一些输出指向文件out但由于not-here.txt不存在,错误将通过标准错误发送,我将重定向到标准输出2>&1

但是,为什么这不起作用:

 ls here.txt not-here.txt 2>&1 1>out 

似乎只有在标准输出指令后进行重定向才能工作? 为什么?

重定向的顺序很重要 。 例如,命令

 ls > dirlist 2>&1 

在命令时将标准输出和标准错误都指向文件dirlist

 ls 2>&1 > dirlist 

仅将标准输出指向文件dirlist,因为在标准输出重定向到dirlist之前,标准错误从标准输出(通常仍指向终端窗口)复制。

起初这可能会让人感到反直觉,但在考虑之后,我们可以理解它。


你可以在man bash找到关于重定向的章节中的这个解释,

REDIRECTION

在执行命令之前,可以使用shell解释的特殊表示法重定向其输入和输出。 重定向允许复制,打开,关闭命令文件句柄,使其引用不同的文件,并可以更改命令读取和写入的文件。 重定向还可用于修改当前shell执行环境中的文件句柄。 以下重定向运算符可以在简单命令之前或出现在任何位置,也可以跟随命令。 重定向按其出现的顺序从左到右处理。

可以在文件描述符号之前的每个重定向可以改为在{varname}forms的单词之后。 在这种情况下,对于除>&-<&-之外的每个重定向运算符,shell将分配大于或等于10的文件描述符并将其分配给varname 。 如果>&-<&-前面有{varname} ,则varname的值定义要关闭的文件描述符。

在以下描述中,如果省略文件描述符号,并且重定向运算符的第一个字符是< ,则重定向指的是标准输入(文件描述符0)。 如果重定向运算符的第一个字符是> ,则重定向引用标准输出(文件描述符1)。

除非另有说明,否则以下描述中的重定向运算符后面的单词将受到括号扩展,波形扩展,参数和变量扩展,命令替换,算术扩展,引用删除,路径名扩展和单词拆分的影响。 如果它扩展为多个单词,bash会报告错误。

请注意,重定向的顺序很重要。 例如,命令

 ls > dirlist 2>&1 

在命令时将标准输出和标准错误都指向文件dirlist

 ls 2>&1 > dirlist 

仅将标准输出指向文件dirlist ,因为在将标准输出重定向到dirlist之前,标准错误与标准输出重复。

编辑:以下命令行可以解释会发生什么

准备

 sudodus@xenial32:~$ touch qwerty;rm asdf rm: cannot remove 'asdf': No such file or directory 

对一个现有文件和一个不存在的文件运行list命令

 sudodus@xenial32:~$ ls qwerty asdf ls: cannot access 'asdf': No such file or directory qwerty 

在重定向标准输出之前重定向错误输出。 只有标准输出被重定向到输出文件。

 sudodus@xenial32:~$ ls qwerty asdf 2>&1 > output-file ;echo '---';cat output-file ls: cannot access 'asdf': No such file or directory --- qwerty 

重定向标准输出后重定向错误输出。 错误输出和标准输出都被重定向到输出文件。

 sudodus@xenial32:~$ ls qwerty asdf > output-file 2>&1 ;echo '---';cat output-file --- ls: cannot access 'asdf': No such file or directory qwerty 

令牌&>可用于重定向标准错误和标准输出。 它可以在bash ,但可能在其他shell中不可用。

 sudodus@xenial32:~$ ls qwerty asdf &> output-file ;echo '---';cat output-file --- ls: cannot access 'asdf': No such file or directory qwerty sudodus@xenial32:~$ 
  • 2>x表示文件名x将接收写入描述符2的数据(也称为stderr,标准错误)
  • …但是当x指定为&1它并不意味着“始终跟随1 ”; 它意味着“复制1的当前属性(然后不管它)”
  • 重定向的应用顺序与在命令行中输入的顺序相同,但在实际执行之前。

这就是为什么2>&1 1>whatever输出stderr到终端的原因。

这就是find / -name mylostfile.txt 3>&1 1>&2 2>&3 | grep -v 'Permission denied' find / -name mylostfile.txt 3>&1 1>&2 2>&3 | grep -v 'Permission denied'交换stderr和stderr,这样你就可以过滤掉一些常见的stderr行,但仍然可以看到所有的stdout。 (这里的描述符3未被程序使用)。

shell会按照它看到的顺序遇到并设置。 在第一种情况下:

 ls here.txt not-here.txt 1>out 2>&1 

输出被重定向,然后标准错误被发送到同一个地方。

在第二种情况下,

 ls here.txt not-here.txt 2>&1 1>out 

标准输出仍然设置到终端,因此标准错误被发送到终端THEN标准输出被更改。 shell已经设置了标准错误。