在许多地方,我发现有人建议您可以按如下方式将 stderr 与 stdout 交换:
命令 3>&2 2>&1 1>&3
这对我来说是倒退的。如果我们将 3 发送到 2,然后立即将 2 发送到 1(现在看起来是同时将 3 和 2 发送到 1)。我认为关于 IO 重定向有一些我不了解的基本知识,但我找不到任何可以澄清它的东西。
您将在 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>&-
哈,我没见过....反正...好像本质上是说先...发送3到2的地址....然后发送2到1的地址....然后将一个发送到 3 的地址……从第一步开始,我们知道这是两个的原始地址……所以你已经交换了它们……不过我自己还没有测试过……
它向后看的原因是因为它是向后。
当您看到
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