stderr和stdout的交换指令为什么是反的?

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

在许多地方,我发现有人建议您可以按如下方式将 stderr 与 stdout 交换:

命令 3>&2 2>&1 1>&3

这对我来说是倒退的。如果我们将 3 发送到 2,然后立即将 2 发送到 1(现在看起来是同时将 3 和 2 发送到 1)。我认为关于 IO 重定向有一些我不了解的基本知识,但我找不到任何可以澄清它的东西。

stdout swap stderr io-redirection
3个回答
3
投票

您将在 http://www.catonmat.net/blog/bash-one-liners-explained-part-three/ 找到详细解释,第 21 节:

$ command 3>&1 1>&2 2>&3 这里我们首先复制文件描述符3到 是标准输出的副本。然后我们将 stdout 复制为 stderr 的副本, 最后我们将 stderr 复制为文件描述符 3 的副本, 这是标准输出。结果我们交换了 stdout 和 stderr。

在给出的链接中有更多细节和图片。关键见解是:

3>&1
的意思是“3 指向 1 指向的地方”。然后
1>&2
说“现在 1 指向 2 指向的地方”(1 现在指向流 2,但是 3 没有跟随......),最后
2>&3
说“现在 2 指向 3 指向的地方(这是流 1).

图形化(但请参阅链接 - 它比我的 ascii-art 好多了):

0 --> /dev/tty0
1 --> /dev/tty1
2 --> /dev/tty2

3>&1
之后:

0 --> /dev/tty0
1 --> /dev/tty1
2 --> /dev/tty2
3 --> /dev/tty1

1>&2
之后:

0 --> /dev/tty0
1 --> /dev/tty2
2 --> /dev/tty2
3 --> /dev/tty1

2>&3
之后:

0 --> /dev/tty0
1 --> /dev/tty2
2 --> /dev/tty1
3 --> /dev/tty1

如您所见,

1
2
已互换。同一个链接建议用
3
关闭临时流
3>&-


1
投票

哈,我没见过....反正...好像本质上是说先...发送3到2的地址....然后发送2到1的地址....然后将一个发送到 3 的地址……从第一步开始,我们知道这是两个的原始地址……所以你已经交换了它们……不过我自己还没有测试过……


0
投票

它向后看的原因是因为它向后。

当您看到

2>&1
时,它看起来像是将 stderr (2) 发送到 stdout (1)。它似乎是这样工作的,因为程序写入 stderr 的数据到达 stdin 管道中的下一个程序。但这不是它的实施方式。该实现将 stdout 文件描述符 (1) 的内容分配给 stderr 文件描述符 (2),以便当程序写入 stderr 或 stdout 时,数据会到达同一个地方。

让我们发明一种替代的、虚构的语法。文件描述符是名称为

stdin
stdout
stderr
fd3
fd4
等的变量,赋值以传统方式从右到左进行。

我们虚构语法中的正常赋值,

stderr = stdout
对应于“向后”shell 语法
2>&1
。因为
>
指向右边,所以看起来赋值是向右的,对吧?错误的。这是从右到左的分配。

所以令人困惑的,看起来落后的

3>&2 2>&1 1>&3
通过一个临时变量变成了一个简单的交换:

fd3 = stderr
stderr = stdout
stdout = fd3

添加

3>&-
关闭临时类似于添加
fd3 = null

© www.soinside.com 2019 - 2024. All rights reserved.