1

我有一个 shell 脚本

find . -name "*.java" -print0 | xargs -0 grep -Lz 'regular_expression'

它以这种方式输出与正则表达式不匹配的文件名:

file1.java
file2.java
...

据我了解,它的工作原理如下:find找到所需的文件并将它们的名称与\0. 然后xargs拆分findwith的输出\0并将它们grep一一提供。

然后我想再添加一个阶段并只获取basename文件。我修改了脚本:

find . -name "*.java" -print0 | xargs -0 grep -LzZ 'regular_expression' | xargs -0 basename

但出现错误。我开始调查并做了一个临时输出:

find . -name "*.java" -print0 | xargs -0 grep -LzZ 'regular_expression' | xargs -0  echo basename

得到了这个:

basename ./file1.java ./file2.java ./subdir/file1.java ./subdir/file2.java

因此,文件名没有被\0. 我不明白为什么在xargs使用 withgrep和不使用xargswith的情况下将它们分开basename

我通过-n1在后者中使用得到了解决方法xargs。但是我仍然不明白为什么我需要它(鉴于我没有在xargswith中使用grep)以及这个参数的作用。

希望您能向我解释-n1在后一种用法中我需要它的作用以及为什么我在前一种用法中不需要它grep

4

2 回答 2

6

-n1告诉每个参数运行一次xargs定的命令。

所以如果你有类似的东西

echo file1 file2 file2 | xargs basename

这相当于

basename file1 file2 file2

但如果你这样做

echo file1 file2 file2 | xargs -n1 basename

这将导致 xargs 运行:

basename file1 
basename file2 
basename file2

至于xargs's-0标志,这是选项的别名,--null它告诉xargs拆分\0而不是默认空格。你需要它,find因为 find 放入了\0with -print0,但结果grep是纯空格分隔的标记。

于 2013-01-18T18:23:13.393 回答
2

文件\0. 不同之处在于您使用的命令。 xargs通常采用其标准输入,将其分解为一个列表(这里,通过在 NUL 上拆分),然后将该列表作为额外参数传递给您的命令。所以当你这样做时:

find . -name "*.java" -print0 | xargs -0 grep -Lz 'regular_expression'

实际运行的是这样的:

grep -Lz 'regular_expression' file1.java file2.java file3.java...

在这里,这-z无关紧要,因为它只影响grep读取标准输入的方式,并且您不会向其标准输入发送任何内容。

因此,当您添加另一个xargs运行时basename,您会得到:

basename file1.java file2.java file3.java...

但是虽然grep会接受任意数量的文件名参数,basename但只接受一个而忽略其他的。

这就是-n 1进来的地方:它告诉xargs将其参数列表分成块(1个),并多次运行该命令。所以现在运行的是:

basename file1.java
basename file2.java
basename file3.java
...

并且所有输出都连接到标准输出上。

于 2013-01-18T18:23:20.177 回答