如何将 -I{} 与 -n 大于 1 的 xargs' 一起使用?

i33*_*36_ 3 xargs

我有大量的文件(数以万计)需要grep通过特定的字符串。少数文件中有空格。文件太多,进程创建开销-n1实际上比文件搜索本身还要大。

这有效,但速度慢得无法使用:

cat filelist | xargs -I{} grep mystring '{}'
Run Code Online (Sandbox Code Playgroud)

所以,我想向每个grep实例传递 1000 个参数,如下所示:

cat filelist | xargs -n1000 -I{} grep mystring '{}'
Run Code Online (Sandbox Code Playgroud)

但这不起作用。似乎{}只有当-n= 1时才有效?!

例子:

进程太多,正确输出:
$ seq 1 10 | xargs -I{} -n1 echo "<{}>"
<1>
<2>
<3>
<4>
<5>
<6>
<7>
<8>
<9>
<10>
大量的进程,还有……什么?
$ seq 1 10 | xargs -I{} -n2 echo "<{}>"
<{}> 1 2
<{}> 3 4
<{}> 5 6
<{}> 7 8
<{}> 9 10

也许我可以用find

Sté*_*las 6

是的,一次-I只能处理一个参数。使用-I,输入也以与不使用(使用-n或不使用)不同的方式解析为参数。

随着-I{}你得到一个字每一个非空行(除非它仍然可以嵌入一个新行用反斜杠引用它),与领先的,而不是结尾的空白字符(其中的列表与执行情况,并现场对一些变化)移除。引号 ( ",'\仍然以与sh's不同的方式处理)。

如果没有-I{},则单词以空格(至少 SPC、TAB 和 NL)分隔,并处理引号。

相比:

$ printf ' a "b c" \n' | xargs -n1 printf '<%s>\n'
<a>
<b c>
$ printf ' a "b c" \n' | xargs -I{} printf '<%s>\n' {}
<a b c >
Run Code Online (Sandbox Code Playgroud)

IMOxargs有点乱,唯一可靠/有用的方法是使用-0-dGNU 扩展。

如果您想一次运行具有多个参数的命令并为每个参数使用不同的占位符,最好使用sh

xargs < filelist -r -n2 sh -c 'printf "1: %s\n2: %s\n" "$1" "$2"' sh
Run Code Online (Sandbox Code Playgroud)

在这里,一次xargs将 2 个参数传递给sh,并sh使用"$1"and进行占位"$2"(另请参见"$@"一次性传递所有参数)。

那是使用 的默认单词标记化xargs。如果filelist要每行包含一个文件,则应使用 GNUxargs-d '\n'.

为了您的grep例子,你并不需要-n,也不-I虽然,只是:

xargs < filelist grep mystring
Run Code Online (Sandbox Code Playgroud)

然后xargs将尽可能多的参数传递给grep(参数添加在最后)。我们可以不用-r这里(一个 GNU 扩展)就好像全filelist是空白一样,仍然在grep没有文件参数的情况下运行(这-r可以防止)应该是无害的,因为它会在filelist.

但是,您可能希望使用-HGNU 选项grep,或将其运行为:

xargs < filelist grep mystring /dev/null
Run Code Online (Sandbox Code Playgroud)

确保grep在找到匹配项时始终打印文件名,即使filelist只包含一个单词。