xDroid's Blog

17 管道 (从新手到菜鸟的Linux教程)

要我说起来呢,shell编程的精髓有两点:一点是它奠定了脚本语言的基础,并实现了交互式命令;另一点就是管道。管道的作用正如其名,就是将程序“连接”在一起,从而简化了许许多多重复繁杂的工作。这一点上,windows cmd就要略逊几筹了。

先举个例子:

$ echo 'Hello World!' | cat
Hello world!

我们知道 cat 的作用是将文件重定向到标准输出(这里的 文件 可以是磁盘上的内容,也可以是 Unix/Linux 意义下各种设备被映射到的操作对象),但是这次 cat 之后没有跟着任何参数,所以 cat 是将什么内容重定向了呢?答案就是在管道符 | 前的 echo 'Hello World!' 命令里。

管道符的使用通常是这样的

command_A | command_B

管道符将 command_A 的标准输出和标准错误 参考这里 定向到 command_B 的标准输入上(这句话似乎不能再通俗了)。考虑到 bash 里所有的变量都是字符串类型,于是利用这个语言特性可以很方便地将信息在命令间传递。

再举几个例子:

$ cat ~/.bashrc | less
# ~/.bashrc: executed by bash(1) for non-login shells.
# see /usr/share/doc/bash/examples/startup-files (in the package bash-doc)
# for examples

作用是先将 ~/.bashrc 的内容输出到标准输出,然后由管道符定向到 less 的输入,于是就可以用 less 愉快地查看了。我同学吐槽我,说你直接 less ~/.bashrc 不就完了= =

下一个例子

$ ps -A | grep pts
 1793 pts/0    00:00:00 zsh
 1890 pts/1    00:01:16 hexo
 4170 pts/0    00:00:00 ps
 4171 pts/0    00:00:00 grep

上一篇介绍 grep 的时候我们是把目标文件(被匹配的文件)作为参数传给 grep ,但是它其实也资瓷从标准输入读入目标内容啊!所以就可以用管道符把 ps -A 的结果(还记得 ps 的功能吗)传递给 grep ——事实上,至少我在平时看进程的时候还是很常用这个搭配的。

但是这样是不行的

$ ls
file
$ ls | rm
rm: missing operand
Try 'rm --help' for more information.

黑人问号?不是说管道符可以把输出重定向给下一个命令的标准输入吗?为什么 rm 说没收到操作数呢?这是因为 rm 要删除的文件名来自于命令后面的参数,而不是来自标准参数啦……

那么怎么才能把输出内容作为命令参数呢?哈哈哈,那就要用到 xargs 了,戳 >这里< 。


尝试了一下,可以确定管道符将标准错误也做了重定向。
$ curl localhost
curl: (7) Failed to connect to localhost port 80: Connection refused
$ curl localhost 2>/dev/null
$ curl localhost | cat
curl: (7) Failed to connect to localhost port 80: Connection refused
$ curl localhost 2>/dev/null | cat
$