【发布时间】:2016-05-09 02:06:13
【问题描述】:
当我运行以下Bash 脚本时,我希望它打印Hello。相反,它会打印一个空行并退出。
echo 'Hello' | echo
为什么piping 从echo 输出到echo 不起作用?
【问题讨论】:
-
你似乎期待第二个
echo表现得像cat。 -
echo $(echo 'Hello')
当我运行以下Bash 脚本时,我希望它打印Hello。相反,它会打印一个空行并退出。
echo 'Hello' | echo
为什么piping 从echo 输出到echo 不起作用?
【问题讨论】:
echo 表现得像 cat。
echo 打印其所有参数。它不是从stdin 读取的。所以第二个echo 打印所有参数(无)并退出,忽略stdin 上的Hello。
对于读取其stdin 并将其打印到stdout 的程序,请使用cat:
$ echo Hello | cat
Hello
【讨论】:
$ echo Hello | xargs echo,默认等价于echo Hello | xargs。
在这种情况下,您使用的管道更正确地称为 匿名 管道,因为它们没有名称(也有 命名管道)。匿名管道仅在相关进程之间工作,例如具有相同父进程的进程。
管道是由 C 运行时库生成的 IO 系统的一部分。这些 流 默认情况下是缓冲的(有一个例外)。基本上,管道只是将一个进程的输出缓冲区连接到另一个进程的输入缓冲区。
使用的前三个流(称为文件描述符)编号为 0、1 和 2。第一个 0 称为 标准输入,或 @987654321 @(C 中使用的名称)。默认情况下,它连接到键盘,但可以使用< 符号或位于管道右侧的程序名称来重定向它。
第二个,1,被称为标准输出,或stdout。默认情况下,它连接到终端屏幕,但可以使用> 符号或位于管道左侧的程序名称来重定向。
所以:
echo 'Hello' | echo
从echo 获取标准输出并将其传递给echo 的标准输入。但是echo 不读取标准输入!所以什么也没发生。
过滤程序处理命令行中指定的文件名。如果没有给出文件名,那么它们读取标准输入。示例包括 cat、grep 和 sed,但不是 echo。例如:
echo 'Hello' | cat
会显示“Hello”,cat 没用(通常是这样)。
echo 'Hello' | cat file1
将忽略来自echo 的输出,只显示file1 的内容。请记住,只有在没有给出文件名的情况下才会读取标准输入。
你认为这显示了什么?
echo 'Hello' | cat < file1 file2
为什么?
最后,第三个流 2 被称为标准错误,或stderr,而这个是无缓冲。它被管道忽略,因为它们只在标准输入和标准输出之间运行。但是,您可以重定向 stderr 以使用 stdout(请参阅 man dup2):
myprog 2>&1 | anotherprog
2>&1 表示“将文件描述符 2 重定向到与 fie 描述符 1 相同的位置”。
以上是正常行为,但是程序可以根据需要覆盖所有这些。例如,它可以从文件描述符 2 中读取。我省略了很多其他细节,包括其他形式的重定向,例如进程替换和here文档。
【讨论】:
管道只能用于从标准输入获取输入的命令。但 echo 不取自标准输入。它将从参数中获取输入并打印它。所以这行不通。为了回应你可以做类似echo $(echo 'hello')
【讨论】:
这是因为echo(内置和/bin/echo)不会从stdin 中读取任何内容。
改用cat:
echo 'Hello' | cat
Hello
或者没有管道:
cat <<< 'Hello'
【讨论】: