我正在玩 i/o shell 重定向。我尝试过的命令(在 bash 中):
ls -al *.xyz 2>&1 1> files.lst
和
ls -al *.xyz 1> files.lst 2>&1
当前文件夹中没有任何*.xyz
文件。
这些命令给了我不同的结果。第一个命令ls: *.xyz: No such file or directory
在屏幕上显示一条错误消息。但是第二个将此错误消息打印到文件中。为什么第一个命令无法将错误输出写入文件?
我正在玩 i/o shell 重定向。我尝试过的命令(在 bash 中):
ls -al *.xyz 2>&1 1> files.lst
和
ls -al *.xyz 1> files.lst 2>&1
当前文件夹中没有任何*.xyz
文件。
这些命令给了我不同的结果。第一个命令ls: *.xyz: No such file or directory
在屏幕上显示一条错误消息。但是第二个将此错误消息打印到文件中。为什么第一个命令无法将错误输出写入文件?
Bash 手册有一个清晰的示例(类似于您的示例),以表明顺序很重要并解释了差异。这是摘录的相关部分(强调我的):
请注意,重定向的顺序很重要。例如,命令
ls >目录2>&1
将标准输出(文件描述符 1)和标准错误(文件描述符 2)都指向文件dirlist,而命令
ls 2>&1 >目录
仅将标准输出定向到文件dirlist,因为在标准输出重定向到dirlist之前,标准错误是标准输出的副本。
这篇文章从 POSIX 的角度解释了它。
由于关键差异而发生混乱。>
重定向不是通过使左操作数 ( stderr
) 指向右操作数 ( stdout
) 而是通过复制右操作数并将其分配给左侧。从概念上讲,通过复制而不是通过引用分配。
因此,从左到右读取这就是 Bash 的解释方式:ls > dirlist 2>&1
意味着重定向stdout
到文件dirlist
,然后重定向stderr
到当前的任何stdout
内容(这已经是文件dirlist
)。但是,ls 2>&1 > dirlist
将重定向stderr
到当前的任何stdout
内容(即屏幕/终端),然后重定向stdout
到dirlist
.
重定向是:
1
stdout(默认值)和2
stderr),则针对该流的后续重定向将引用已重定向的版本。1
例如,如果您在较早的重定向中将文件描述符指定为目标,则1
意味着当时被锁定,即使1
稍后重定向也是如此。应用于问题中的示例:
>file 2>&1
:
>file
首先将stdout(文件描述符1
,不>
以文件描述符编号作为前缀暗示)重定向到输出文件file
2>&1
然后将 stderr ( 2
) 重定向到已经重定向的stdout ( 1
)。file
.2>&1 >file
:
2>&1
首先将 stderr 重定向到当时的原始标准输出;由于文件描述符2
不参与进一步的重定向,因此 stderr 输出将转到当时定义的任何标准输出-即原始标准输出,因为这是第一次重定向。
>file
然后将原始标准输出重定向到file
- 但这对已经锁定的标准错误重定向不再有影响。file
在这个错误:
ls: *.xyz: No such file or directory
正在stderr
由ls
二进制写入。
但是在这个命令中:
ls -al *.xyz 2>&1 1> files.lst
您首先重定向 stderr
到stdout
默认情况下转到tty
(终端)
然后你重定向stdout
到一个文件files.lst
,但是请记住,stderr 不会重定向到文件,因为你必须在stderr
重定向stdout
之前重定向 。在这种情况下,您仍然会被写入。stdout
file
stderr
tty
但是在第二种情况下,您更改重定向的顺序(首先stdout
到file
然后stderr
到stdout
),并且正确地重定向stderr
到file
也被stdout
.
因为顺序确实很重要。在第一种情况下,您首先将 stderr (2) 重定向到 stdout (1)。然后将 (1) 重定向到一个文件。但是 stderr (2) 仍然指向运行命令的 shell 的标准输出。在这种情况下,将 (1) 指向文件不会更改 (2) 指向的输出设备,因此它仍会转到终端。
在第二种情况下,您将 stdout (1) 重定向到文件。然后你将stderr(2)指向同一个地方1被指向,也就是文件,所以错误信息转到文件。
重定向从左到右处理
他们是一样的:
我记住整件事的方法
让我们想象我们正在玩一个游戏。有一座有 2 个破损部分的桥。