shell脚本最棒的特性之一就是可以轻松地将多个命令或工具组合起来生成输出。一个命令的输出可以作为另一个命令的输入,而这个命令的输出又会传递至另一个命令,依次类推。这种命令组合的输出可以被存储在一个变量中。这则攻略将演示如何组合多个命令以及如何读取其输出。

1. 预备知识

输入通常是通过stdin或参数传递给命令。输出要么出现在stderr,要么出现在stdout。当我们组合多个命令时,同时将stdin用于输入,stdout用于输出。

这些命令被称为过滤器(filter)。我们使用管道(pipe)来连接每一个过滤器。管道操作符是"|"。例如:

$ cmd1 | cmd2 | cmd3

这里我们组合了三个命令。cmd1的输出传递给cmd2,而cmd2的输出传递给cmd3,最终(来自cmd3)的输出将会被打印或导入某个文件。

2. 实战演练

请看下面的代码:

$ ls | cat -n > out.txt

ls的输出(当前目录内容的列表)被传给cat -ncat -n为通过stdin所接收到输入内容加上行号,然后将输出重定向到文件out.txt。

我们可以用下面的方法读取命令序列的输出:

cmd_output=$(COMMANDS)

这种方法也被称为子shell(subshell)。例如:

cmd_output=$(ls | cat -n)
echo $cmd_output

另一种被称为反引用(back-quote)的方法也可以用于存储命令输出:

cmd_output=`COMMANDS`

例如:

cmd_output=`ls | cat -n`
echo $cmd_output

反引用与单引号可不是一回事,它位于键盘的 ~ 键上。

3. 补充内容

有很多种方法可以给命令分组。来看看其中的几种。

  1. 利用子shell生成一个独立的进程

    子shell本身就是独立的进程。可以使用()操作符来定义一个子shell:

    pwd;
    (cd /bin; ls);
    pwd;
    

    当命令在子shell中执行时,不会对当前shell有任何影响;所有的改变仅限于子shell内。例如,当用cd命令改变子shell的当前目录时,这种变化不会反映到主shell环境中。

    pwd命令打印出工作目录的路径。

    cd命令将当前目录更改为给定的目录路径。

  2. 通过引用子shell的方式保留空格和换行符

    假设我们使用子shell或反引用的方法将命令的输出读入一个变量中,可以将它放入双引号中,以保留空格和换行符(\n)。例如:

    $ cat text.txt
    1
    2
    3
     
    $ out=$(cat text.txt)
    $ echo $out
    1 2 3 # 丢失了换行符 \n
    $ out="$(cat tex.txt)"
    $ echo $out
    1
    2
    3