为什么重定向+管道(2>&1 |)合并两个流而不是将stderr移动到stdout?

问题描述 投票:0回答:4

我读到重定向是从左到右处理的。所以在这个例子中

 command 2>&1 | less

有人会认为 fd 2 首先被定向到 fd 1,然后 fd 1 被发送到管道。所以 fd 1 和 2 指向不同的地方。

但实际上这里的 fd 1 和 2 都指向管道,因为由于某种原因,fd 1 首先发送到管道,然后 fd 2 发送到 fd 1。为什么在这种情况下从右到左处理重定向?

linux bash http-redirect io-redirection
4个回答
3
投票

管道不是重定向,因此实际上重定向(您的示例中只有一个)正在按照您的想法进行处理。 管道最后是一个单独的东西。


3
投票

原因是管道与重定向不同。重定向影响一个命令,而管道连接两个命令。


3
投票

fd 2 指向 fd 1 所指向的位置(即 stdout)。在

command 2>&1 | less

在重定向生效之前,stdout 已经指向管道!

更详细的解释请参见:

http://www.linuxtutorialblog.com/post/tutorial-the-best-tips-tricks-for-bash

# ...
# Well, here's a thing you should remember: bash reads command statements from 
# the left to the right, but, before that, determines if there are multiple command 
# statements and in which way they are separated. Therefore, bash already read 
# and applied the "|" pipe symbol and stdout is already pointing to the pipe.
# ...

0
投票

这是因为管道首先“发生”。

command 2>&1 | less
  1. 父进程见“|”运算符,它创建 2 个文件描述符 (fd),第一个用于读取(即读取结束),第二个用于写入(即写入结束)。
  2. “less”的子进程将其标准输入
  3. fd 更改为“|” 的写入结束 fd
  4. “command 2>&1”的子进程将其标准输出
  5. fd更改为“|”的读取端fd
  6. “command 2>&1”的子进程将其 stderr
  7. fd 重定向到 stdout fd
示例:

$ strace -qf -e 'dup3,pipe2' sh -c 'ls -al file-exist file-doesnt-exist 2>&1 | grep f' pipe2([3, 4], 0) = 0 # Parent create 2 fds, fd4 for | [pid 317043] dup3(3, 0, 0) = 0 # 2nd process changes stdin to fd3 [pid 317042] dup3(4, 1, 0) = 1 # 1st process changes stdin to fd3 [pid 317042] dup3(1, 2, 0) = 2 # 1st process redirects stderr (fd2) to stdout (fd1)
    
© www.soinside.com 2019 - 2024. All rights reserved.