Linux Shell管道详解

1年前 (2024-04-27)
通过前面的学习,我们已经知道了怎样从文件重定向输入,以及重定向输出到文件。Shell 还有一种功能,就是可以将两个或者多个令(程序或者进程)连接到一起,把一个令的输出作为下一个令的输入,以这种方式连接的两个或者多个令就形成了管道(pipe)

Linux 管道使用竖线|连接多个令,这被称为管道符。Linux 管道的具体语法格式如下:

command1 | command2

command1 | command2 [ | commandN... ]

当在两个令之间设置管道时,管道符|左边令的输出就变成了右边令的输入。只要个令向标准输出写入,而第二个令是从标准输入读取,那么这两个令就可以形成一个管道。大部分的 Linux 令都可以用来形成管道。

这里需要注意,command1 必须有正确输出,而 command2 必须可以处理 command2 的输出结果;而且 command2 只能处理 command1 的正确输出结果,不能处理 command1 的错误信息。

为什么使用管道?

我们先看下面一组令,使用 mysqldump(一个数据库备份程序)来备份一个叫做 wiki 的数据库:

mysqldump -u root -p '123456' wiki > /tmp/wikidb.backup
gzip -9 /tmp/wikidb.backup

scp /tmp/wikidb.backup username@remote_ip:/backup/mysql/

上述这组令主要做了如下任务:

  • mysqldump 令用于将名为 wike 的数据库备份到文件 /tmp/wikidb.backup;其中-u-p选项分别指出数据库的用户名和密码。
  • gzip 令用于压缩较大的数据库文件以节省磁盘空间;其中-9表示最慢的压缩速度最好的压缩效果。
  • scp 令(secure copy,安全拷贝)用于将数据库备份文件到 IP 地址为 remote_ip 的备份服务器的 /backup/mysql/ 目录下。其中username是登录远程服务器的用户名,令执行后需要输入密码。


上述三个令依次执行。然而,如果使用管道的话,你就可以将 mysqldump、gzip、ssh 令相连接,这样就避免了创建临时文件 /tmp/wikidb.backup,而且可以同时执行这些令并达到相同的效果。

使用管道后的令如下所示:

mysqldump -u root -p '123456' wiki | gzip -9 | ssh username@remote_ip "cat > /backup/wikidb.gz"

这些使用了管道的令有如下特点:

  • 令的语法紧凑并且使用简单。

  • 通过使用管道,将三个令串联到一起就完成了远程 mysql 备份的复杂任务。

  • 从管道输出的标准错误会混到一起。


上述令的数据流如下图所示:

Linux Shell管道演示图

重定向和管道的区别

乍看起来,管道也有重定向的作用,它也改变了数据输入输出的方向,那么,管道和重定向之间到底有什么不同呢?

简单地说,重定向操作符>将令与文件连接起来,用文件来接收令的输出;而管道符|将令与令连接起来,用第二个令来接收个令的输出。如下所示:

command > file

command1 | command1

有些读者在学习管道时会尝试如下的令,我们来看一下会发生什么:

command1 > command2

答案是,有时尝试的结果将会很糟糕。这是一个实际的例子,一个 Linux 系统管理员以超级用户(root 用户)的身份执行了如下令:

cd /usr/bin

ls > less

条令将当前目录切换到了大多数程序所存放的目录,第二条令是告诉 Shell 用 ls 令的输出重写文件 less。因为 /usr/bin 目录已经包含了名称为 less(less 程序)的文件,第二条令用 ls 输出的文本重写了 less 程序,因此破坏了文件系统中的 less 程序。

这是使用重定向操作符错误重写文件的一个教训,所以在使用它时要谨慎。

Linux管道实例

【实例1】将 ls 令的输出发送到 grep 令:

[c.biancheng网站站点" rel="nofollow" /> log.txt

上述令是查看文件 log.txt 是否存在于当前目录下。

我们可以在令的后面使用选项,例如使用-al选项:

[c.biancheng网站站点" rel="nofollow" /> log.txt

管道符|与两侧的令之间也可以不存在空格,例如将上述令写作ls -al|grep log.txt;然而我还是在管道符|和两侧的令之间使用空格,以增加代码的可读性。

我们也可以重定向管道的输出到一个文件,比如将上述管道令的输出结果发送到文件 output.txt 中:

[c.biancheng网站站点" rel="nofollow" />

cat /var/log/message | less


【实例3】查看指定程序的进程运行状态,并将输出重定向到文件中。

[c.biancheng网站站点" rel="nofollow" />

[c.biancheng网站站点" rel="nofollow" />

[c.biancheng网站站点" rel="nofollow" /> command1 < input.txt | command2

command1 < input.txt | command2 -option | command3


例如,使用 tr 令从 os.txt 文件中获取输入,然后通过管道将输出发送给 sort 或 uniq 等令:

[c.biancheng网站站点" rel="nofollow" /> command1 | command2 | ... | commandN > output.txt

command1 < input.txt | command2 | ... | commandN > output.txt


【实例1】使用 mount 令显示当前挂载的文件系统的信息,并使用 column 令格式化列的输出,将输出结果保存到一个文件中。

[c.biancheng网站站点" rel="nofollow" />

[c.biancheng网站站点" rel="nofollow" />