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

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

因此我正在尝试学习如何将标准输出和标准错误传递到各个区域。

假设我有一个包含here.txtalone 的文件夹。

所以如果我这么做

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

似乎只有在标准输出指令之后执行重定向才会起作用?为什么?

答案1

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

ls > dirlist 2>&1

将标准输出和标准错误都定向到文件 dirlist,而命令

ls 2>&1 > dirlist

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

一开始这可能看起来违反直觉,但经过思考之后,我们就可以理解。


man bash您可以在有关重定向的章节中找到此解释,

重定向

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

每个重定向前面可以加上文件描述符编号,但也可以加上形式为 的单词{varname}。在这种情况下,对于除>&-和 之外的每个重定向运算符<&-,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

  • 2>x表示 filenamex将接收写入描述符的数据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'要交换 stderr 和 stderr,这样你就可以过滤掉一些常见的 stderr 行,但仍然可以看到所有的 stdout。(这里的描述符 3 未被程序使用)。

答案3

shell 按照它看到的顺序来处理和设置事物。在第一种情况下:

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

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

在第二种情况下,

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

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

相关内容