grep "hehe" < test.sh
输入重定向 - 当然仅适用于单个文件,而 cat 适用于任意数量的输入文件。
考虑符号:
grep "hehe" $(cat test.sh)
grep "hehe" `cat test.sh`
在这种情况下,它们是等价的;在嵌套使用中使用“$(cmd)”表示法要容易得多,例如:
x=$(dirname $(dirname $(which gcc)))
x=`dirname \`dirname \\\`which gcc\\\`\``
(这为您提供了安装 GCC 的基本目录,以防您想知道。)
在grep 示例中,发生的情况是test.sh 的内容被读取并拆分为空格分隔的单词,并且每个这样的单词都作为grep 的参数提供。由于grep 处理"hehe" 之后的单词(当然,grepnot 看到双引号 - 在这种情况下不需要它们;作为一般规则,使用单引号引号而不是双引号,尤其是在复杂字符串(如经常使用 shell 元字符的正则表达式)周围)...正如我所说,grep 将"hehe" 之后的单词视为文件名,并尝试打开每个文件,通常会失败郁闷,因为文件不存在。这就是为什么该符号在这种情况下不合适的原因。
在重新审视这个问题之后,还有更多可以说的——还没有说的。
首先,许多 Unix 命令被设计为“过滤器”;他们从一些文件中读取输入,以某种方式对其进行转换,然后将结果写入标准输出。此类命令专为在命令管道中使用而设计。示例包括:
- 猫
- grep
- 特罗夫和亲戚
- awk(带有警告)
- sed
- 排序
所有这些过滤器都具有相同的一般行为:它们采用命令行选项来控制它们的行为,然后它们要么读取指定为命令行参数的文件,要么,如果没有这样的参数,它们读取它们的标准输入。有些(如sort)可以选择控制其输出的去向而不是标准输出,但这相对不常见。
有一些纯过滤器 - tr 就是其中之一 - 严格读取标准输入并写入标准输出。
其他命令有不同的行为。 Eric Raymond 为“The Art of UNIX Programming”中的命令类型提供了分类。
一些命令会在标准输出中生成文件名列表 - 两个经典命令是 ls 和 find。
有时,您希望将文件名生成器的输出用作过滤器的命令行参数。有一个程序可以自动执行此操作 - 它是 xargs。
通常,您会使用:
find . -name '*.[chyl]' | xargs grep -n magic_name /dev/null
这将生成扩展名为“.c”、“.h”、“.y”和“.l”的文件的完整列表(C 源代码、标题、Yacc 和 Lex 文件)。当xargs 读取列表时,它会创建以grep -n magic_name /dev/null 开头的命令行,并将每个单词(由空格分隔)作为参数。
在过去,Unix 文件名不包含空格。在 Mac 和 Windows 的影响下,这样的空间现在已经司空见惯。 find 和 xargs 的 GNU 版本有互补的选项来处理这个问题:
find . -name '*.[chyl]' -print0 | xargs -0 grep -n magic_name /dev/null
'-print0' 选项的意思是“打印以 NUL '\0' 结尾的文件名”(因为不能出现在(简单)文件名中的唯一字符是 '/' 和 NUL,显然,' /' 可以出现在路径名中)。对应的 '-0' 告诉 xargs 查找以 NUL 结尾的名称,而不是空格分隔的名称。