因此我正在尝试学习如何将标准输出和标准错误传递到各个区域。
假设我有一个包含here.txt
alone 的文件夹。
所以如果我这么做
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 已经设置了标准错误。