对话 UNIX,第 13 部分: 另外十种命令行组合( 三 )


为了使得 find 更具可移植性,并且类似于 Spotlight 的搜索特性,那么应该使用 -print0 -follow -iname pattern。
收集许多命令的输出的简单方法
通过使用 > output 和 >> output 修饰符,您可以很容易地捕获一个命令行的输出,其中前者用于创建或者覆盖文件 output,而后者则将内容追加到 output。您可以组合使用任何修饰符以生成一系列命令的文本,如果您正尝试对系统状态进行快照,这种方法是非常有价值的,例如:
$ ps > state.`date ' %F'`
$ w >> state.`date ' %F'`
反勾号或反引号操作符 (``) 可以对命令进行扩展 。在 Shell 对命令行进行解释时,将执行反勾号之间的命令,并在最终的扩展结果中使用该命令的输出 。在本示例中,参数周围的单引号用于保持参数不变,从而可以避免 Shell 对和 % 进行解释 。
在执行了这两个命令之后,创建了文件 state.YYYY-MM-DD,如 state.2007-08-05,其内容与以下所示类似:
 PID TTY TIME CMD
9997 pts/100:00:00 zsh
10351 pts/100:00:00 ps
17:56:04 up 21 days, 2:53, 2 users, load average: 0.89, 0.94, 0.91
USER TTY FROM LOGIN@IDLEJCPUPCPU WHAT
adamgood pts/0c-67-169-182-255 Sat170.00s 0.37s 0.36s pine
mstreich pts/1cpe-071-065-224- 17:170.00s 0.01s 0.00s w
不过,每次输入反勾号操作是非常麻烦的 。您可以使用下面的命令来代替这个序列:
$ file=state.`date ' %F'`
$ ps > $file
$ w >> $file
但是,虽然这样做稍微有效一些,但仍然可能出现错误,因为在第二个或者后续的命令中,很可能使用 > 而不是 >> 。要捕获一系列命令的输出,最简单的方法是使用大括号 ({ }) 将命令括起来 。
$ { ps; w } > state.`date ' %F'`
ps 命令运行(列出用户当前的进程),然后是 w(它将显示谁正在使用这台计算机),并将收集到的输出保存到一个文件中 。
注意: 您还可以在圆括号中嵌入一个命令序列,以得到相同的结果;然而,两者之间有一个重要的区别 。在圆括号中的系列命令将在一个子 Shell 中运行,并且不会对当前 Shell 的状态产生影响 。
例如,您可能希望运行这个序列:$ { cd $HOME; ls
 -1}; pwd
它将与下面的命令产生相同的输出:$ (cd $HOME; ls); pwd
大括号中的命令更改了当前 Shell 的工作目录 。后面的这种技术则无能为力 。是使用组合还是子 Shell,这取决于您的目的,尽管子 Shell 的功能更强大一些,下面将对其进行描述 。
子 Shell 可以为您提供帮助!
尽管通常运行子 Shell 将聚合的输出通过管道传递给单个命令,但您还可以使用子 Shell 对命令进行扩展,就像反勾号那样 。然而更有价值的是,子 Shell 可以包含另一个子 Shell,所以还可以进行嵌套扩展 。
让我们来看看下面简单的例子 。
$ {ps; w} > state.$(date ' %F')
【对话 UNIX,第 13 部分: 另外十种命令行组合】这个命令与 { ps; w } > state.`date ' %F'` 是相同的 。$( ) 符号运行圆括号中的命令,然后使用输出来替换自己 。换句话说,$() 可以进行扩展,就像反勾号一样 。然而,与反勾号不同的是,$( ) 非常复杂,并且甚至可以包括其他 $( ) 扩展 。下面提供了一些示例:
$ (cd $(grep strike /etc/passwd | cut -f6 -d':'); ls)
这个命令在密码文件中搜索用户 strike 对应的条目,提取其 home 目录(密码文件中的第 6 个字段,如果您从 0 开始数)字段,更改到这个目录,并列出其中的内容 。grep /etc/passwd strike | cut -f6 -d':' 的输出将在执行任何其他操作之前进行扩展 。
下面是另一个示例,这次的用户名来自于 whoami 的结果:
(cd $(grep $(whoami) /etc/passwd | cut -f6 -d':'); ls)

推荐阅读