Tra*_*net 34 command-line bash redirect
我试图重定向都stdout和stderr到文件的今天,我碰到这个就来了:
<command> > file.txt 2>&1
Run Code Online (Sandbox Code Playgroud)
这显然重定向stderr到stdout第一个,然后结果stdout被重定向到file.txt.
但是,为什么不是顺序<command> 2>&1 > file.txt?人们自然会将此解读为(假设从左到右执行)首先执行的命令,然后stderr重定向到stdout,然后将结果stdout写入file.txt. 但以上只重定向stderr到屏幕。
shell 如何解释这两个命令?
Arr*_*cal 43
当您运行<command> 2>&1 > file.txtstderr 时,会被重定向2>&1到 stdout 当前所在的位置,即您的终端。之后,stdout 被重定向到文件>,但stderr 不随它重定向,因此保留为终端输出。
使用<command> > file.txt 2>&1stdout 首先通过 重定向到文件>,然后2>&1将 stderr 重定向到 stdout 要去的地方,也就是文件。
一开始可能看起来违反直觉,但是当您以这种方式考虑重定向时,并记住它们是从左到右处理的,这更有意义。
mur*_*uru 20
如果你追踪它可能是有意义的。
一开始,stderr 和 stdout 去到同样的事情(通常是终端,我在这里称之为pts):
fd/0 -> pts
fd/1 -> pts
fd/2 -> pts
Run Code Online (Sandbox Code Playgroud)
我在这里通过文件描述符编号指的是 stdin、stdout 和 stderr :它们分别是文件描述符 0、1 和 2。
现在,在第一组重定向中,我们有> file.txt和2>&1。
所以:
> file.txt:fd/1现在去file.txt。随着>,1是什么都没有指定时隐含的文件描述符,所以这是1>file.txt:
fd/0 -> pts
fd/1 -> file.txt
fd/2 -> pts
Run Code Online (Sandbox Code Playgroud)2>&1:fd/2现在去任何fd/1 目前去的地方:
fd/0 -> pts
fd/1 -> file.txt
fd/2 -> file.txt
Run Code Online (Sandbox Code Playgroud)另一方面,使用2>&1 > file.txt,顺序颠倒:
2>&1:fd/2现在去任何fd/1当前去的地方,这意味着没有任何变化:
fd/0 -> pts
fd/1 -> pts
fd/2 -> pts
Run Code Online (Sandbox Code Playgroud)> file.txt:fd/1现在转到file.txt:
fd/0 -> pts
fd/1 -> file.txt
fd/2 -> pts
Run Code Online (Sandbox Code Playgroud)重要的一点是重定向并不意味着重定向的文件描述符将跟随目标文件描述符的所有未来更改;它只会呈现当前状态。
Zan*_*nna 11
我认为认为 shell 会先在左侧设置重定向,并在设置下一个重定向之前完成它会有所帮助。
William Shotts的 Linux 命令行说
首先我们将标准输出重定向到文件,然后我们将文件描述符 2(标准错误)重定向到文件描述符 1(标准输出)
这是有道理的,但随后
请注意,重定向的顺序很重要。标准错误的重定向必须总是在重定向标准输出之后发生,否则它不起作用
但实际上,我们可以在将 stderr 重定向到具有相同效果的文件后将 stdout 重定向到 stderr
$ uname -r 2>/dev/null 1>&2
$
Run Code Online (Sandbox Code Playgroud)
因此,在 中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
Run Code Online (Sandbox Code Playgroud)
我们可能认为这会将 stdout 处理到与 stderr 相同的位置,但事实并非如此,它首先将 stdout 重定向到 stderr(屏幕),然后只重定向 stderr,就像我们反过来尝试一样...
我希望这会带来一点光明......
Ano*_*noE 10
你已经得到了一些很好的答案。让我强调一下,这里涉及两个不同的概念,理解它们有很大帮助:
您的文件描述符只是一个数字 0...n,它是您进程中文件描述符表中的索引。按照惯例,STDIN=0,STDOUT=1,STDERR=2(注意STDIN这里的术语等只是一些编程语言和手册页中约定使用的符号/宏,没有一个名为 STDIN 的实际“对象”;对于本次讨论的目的,STDIN为0 等)。
该文件描述符表本身不包含有关实际文件的任何信息。相反,它包含一个指向不同文件表的指针;后者包含有关实际物理文件(或块设备、管道或 Linux 可通过文件机制寻址的任何其他内容)的信息和更多信息(即,是否用于读取或写入)。
因此,当您在 shell 中使用>或<时,您只需替换相应文件描述符的指针以指向其他内容。语法2>&1简单地将描述符 2 指向任何 1 点。> file.txt简单地打开file.txt以进行写入并让 STDOUT(文件描述符 1)指向它。
还有其他好东西,例如2>(xxx) (即:创建一个新进程 running xxx,创建一个管道,将新进程的文件描述符 0 连接到管道的读取端,并将原始进程的文件描述符 2 连接到管道的写入端管道)。
这也是除 shell 之外的其他软件中“文件处理魔术”的基础。例如,您可以在 Perl 脚本dup中将 STDOUT 文件描述符连接到另一个(临时)文件描述符中,然后将 STDOUT 重新打开到新创建的临时文件。从现在开始,您自己的 Perl 脚本的所有 STDOUT 输出以及system()该脚本的所有调用都将在该临时文件中结束。完成后,您可以dup将 STDOUT重新设置为保存它的临时描述符,然后一切都和以前一样。您甚至可以同时写入该临时描述符,因此当您的实际 STDOUT 输出进入临时文件时,您仍然可以实际将内容输出到真正的STDOUT(通常是用户)。
要将上面给出的背景信息应用于您的问题:
shell 执行命令和流重定向的顺序是什么?
左到右。
<command> > file.txt 2>&1
fork 关闭新进程。file.txt并将其指针存储在文件描述符 1 (STDOUT) 中。file.txt当然也是已经打开的)。exec 这 <command>这显然首先将 stderr 重定向到 stdout,然后将生成的 stdout 重定向到 file.txt。
如果只有一张桌子,这是有道理的,但如上所述,有两张桌子。文件描述符不会递归地相互指向,认为“将 STDERR 重定向到 STDOUT”是没有意义的。正确的想法是“将 STDERR 指向 STDOUT 指向的任何地方”。如果稍后更改 STDOUT,STDERR 会保持原样,它不会神奇地随着对 STDOUT 的进一步更改而发生。
| 归档时间: |
|
| 查看次数: |
5236 次 |
| 最近记录: |