bash 如何在避免“太多论点”的同时进行 grep

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16086834/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 05:13:00  来源:igfitidea点击:

How can I grep while avoiding 'Too many arguments'

linuxbashgrep

提问by Justin S

I was trying to clean out some spam email and ran into an issue. The amount of files in queue, were so large that my usual command was unable to process. It would give me an error about too many arguments.

我试图清除一些垃圾邮件,但遇到了问题。队列中的文件数量太大,以至于我通常的命令无法处理。它会给我一个关于太多参数的错误。

I usually do this

我通常这样做

grep -i [email protected] 1US* | awk -F: '{print }' | xargs rm

1US* can be anything between 1US[a-zA-Z]. The only thing I could make work was running this horrible contraption. Its one file, with 1USa, 1USA, 1USb etc, through the entire alphabet. I know their has to be a way to run this more efficiently.

1US* 可以是 1US[a-zA-Z] 之间的任何值。我唯一能做的就是运行这个可怕的装置。它的一个文件,包含 1USa、1USA、1USb 等,贯穿整个字母表。我知道他们必须是一种更有效地运行它的方法。

grep -s $SPAMMER /var/mailcleaner/spool/exim_stage1/input/1USa* | awk -F: '{print }' | xargs rm
grep -s $SPAMMER /var/mailcleaner/spool/exim_stage1/input/1USA* | awk -F: '{print }' | xargs rm

采纳答案by Guido

Run several instances of grep. Instead of

运行多个 grep 实例。代替

grep -i [email protected] 1US* | awk '{...}' | xargs rm

do

(for i in 1US*; do grep -li user@domain "$i"; done) | xargs rm

Note the -l flag, since we only want the file name of the match. This will both speed up grep (terminate on first match) and makes your awk script unrequired. This could be improved by checking the return status of grep and calling rm, not using xargs (xargs is very fragile, IMO). I'll give you the better version if you ask.

注意 -l 标志,因为我们只想要匹配的文件名。这将加速 grep(在第一场比赛时终止)并使您的 awk 脚本不再需要。这可以通过检查 grep 的返回状态并调用 rm 来改进,而不是使用 xargs(xargs 非常脆弱,IMO)。如果你问,我会给你更好的版本。

Hope it helps.

希望能帮助到你。

回答by hek2mgl

you can use findto find all files which name's starting with the pattern '1US'. Then you can pipe the output to xargs which will take care, that the argument list will not growing to much and handle the grep call. Note that I've used a nullbyte to separate filenames for xargs. This avoids problems with problematicfile names. ;)

您可以find用来查找名称以模式“1US”开头的所有文件。然后,您可以将输出通过管道传输到 xargs,这将确保参数列表不会增长太多并处理 grep 调用。请注意,我使用空字节来分隔 xargs 的文件名。这避免了有问题的文件名的问题。;)

find -maxdepth 1 -name '1US*' -printf '%f
# List the files that match
find /path/to/input/ -type f -exec grep -qiF [email protected] \{\} \; -print
# Once you're sure you've got it right
find /path/to/input/ -type f -exec grep -qiF [email protected] \{\} \; -delete
' | xargs -0 grep -u user@domain | awk ...

回答by MattH

The -execargument to findis useful here, I've used this myself in similar situations.

-exec参数在find这里很有用,我自己在类似的情况下使用过这个。

E.g.

例如

ls 1US* | xargs grep -i [email protected] | awk -F: '{print }' | xargs rm

回答by Ziffusion

Using xargs is more efficient than using "find ... -exec grep" because you have less process creations etc.

使用 xargs 比使用“find ... -exec grep”更有效,因为你创建的进程更少等等。

One way to go about this would be:

解决这个问题的一种方法是:

find . -iname "1US*" -exec rm {} \;

But easier would be:

但更容易的是:

find . -name '1US*' | \
while read x; do grep -iq user@domain "$x" && rm "$x"; done

回答by Symaxion

Use findand a loop instead of xargs.

使用find和循环而不是xargs.

##代码##

This uses pipes and loops instead of arguments (both for grepand rm) and prevents issues related with limits on arguments.

这使用管道和循环而不是参数(forgreprm)并防止与参数限制相关的问题。