一个命令如何可以有多个输出?

一个命令如何可以有多个输出?

这个答案在最底部,Gilles 提到一个命令可以有多个输出或输入。

是的,有cat foo bar | something, 用于将foobar作为输入,还有tee用于输出;但这似乎并不是他真正所说的。

一个程序如何可以有多个输入或输出?

答案1

这个cat foo bar例子不是我的意思。这里cat一次只有一个输入和一个输出。

tee是一个例子:它输出到所有参数,同时加上它的标准输出。使用与中相同类型的 ASCII 艺术图我之前的回答,这是tee foo bar它在终端中运行时的样子。

   +------------------+    
   |       tee        |    
===|<stdin            |         +------------+
→  |                  |         |  terminal  |
   |           stdout>|=========|<input      |
   |                  |   → ##==|<           |
   |                  |     ||  +------------+
   |           stderr>|=====##
   |                  |   →
   |                  |       +-------------+
   |                3>|=======|> file "foo" |
   |                  |   →   +-------------+
   |                  |       +-------------+
   |                4>|=======|> file "bar" |
   |                  |   →   +-------------+
   |                  |    
   +------------------+    

在此示例中,tee将“有用”输出发送到三个通道:发送到终端(因为这是其标准输出连接到的位置)和两个文件。此外,tee还多了一个错误输出通道。

一个程序通常具有三个输入/输出通道,由它们的标识文件描述符数字:

  • 标准输入(简称stdin,文件描述符号0);
  • 标准输出(简称stdout,文件描述符号1);
  • 标准错误(简称stderr,文件描述符编号2)。

文件描述符 0、1 和 2 的目的只是一个约定问题——没有什么强制程序不能尝试写入文件描述符 0 或从描述符 1 和 2 读取——但这是一个几乎普遍遵循的约定。

如果从终端运行程序,文件描述符 0、1 和 2 开始时会连接到该终端,除非它们已被重定向。其他文件描述符一开始是关闭的,并且在程序打开其他文件时将被使用。

特别是,所有命令都有两个输出:标准输出(对于命令的有效负载,“有用”输出)和标准错误(对于错误或信息性消息)。

shell ( command1 | command2 | command3 | …) 中的管道将每个命令的标准输出连接到下一个命令的标准输入。所有命令的标准错误都会发送到终端(除非重定向)。

Shell 提供了重定向其他文件描述符的方法。您可能遇到过2>&12>file重定向标准错误。看 什么时候会使用额外的文件描述符?另一个帖子链接到其他文件描述符的操作示例。

功能丰富的 shell 还提供流程替代将文件重定向推广到管道命令,这样您就不会局限于每个命令具有单个输入和单个输出的线性管道。

很少有命令尝试访问大于 2 的文件描述符,除非它们打开了文件(打开文件会选择一个空闲文件描述符并将其编号返回给应用程序)。 GnuPG 就是一个例子,它期望读取数据以在其标准输入上进行加密/解密/签名/验证,并将结果写入标准输出。可以使用该选项告诉它读取不同文件描述符上的密码--passphrase-fd。 GnuPG 还具有报告其他文件描述符上的状态数据的选项,因此您可以在 stdout 上输出有效负载,在 stderr 上输出错误消息,并在另一个文件描述符上获得状态信息。下面是一个使用管道命令的输出作为密码的示例:

echo fjbeqsvfu | rot13 | gpg -d --passphrase-fd=3 3<&0 <file.encrypted >file.plaintext

答案2

命令可以有多个输出流,我并不是指写入文件或套接字。考虑大多数 GNU 工具(例如grep)将错误打印到 stderr 并将预期输出打印到 stdout。虽然在交互式 shell 中两者都会合并 (2>&1),但您仍然可以单独处理它们。它并没有结束,因为如果程序或代码块支持,您可以使用额外的文件描述符。

人为的例子:

{
  grep NORMAL log.txt
  grep WARN log.txt 1>&3
  grep ERROR log.txt 1>&4
} 1> normals.txt 3> warnings.txt 4> errors.txt # 2>/dev/null

答案3

是的。例如,cat foo bar | less给出两个输入(文件 foo 和文件 bar)并将它们都输出到 less。vim foo*会将所有以 foo 开头的文件输出到 vim 中。查看每个文件后,您可以使用 :n (如果您更改了任何内容,则使用 :wn )切换到下一个输出。我认为吉尔斯解释得很好。如果您使用管道 ( | ),它将获取一个命令的输出,将其输入到另一命令中,然后输出结果。这是多个输出的另一个例子。

相关内容