【问题标题】:How can I grep while avoiding 'Too many arguments' [duplicate]如何在避免“参数过多”的同时进行 grep [重复]
【发布时间】:2013-04-11 19:07:41
【问题描述】:

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

我通常这样做

grep -i user@domain.com 1US* | awk -F: '{print $1}' | xargs rm

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

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

【问题讨论】:

标签: linux bash grep


【解决方案1】:

运行多个 grep 实例。而不是

grep -i user@domain.com 1US* | awk '{...}' | xargs rm

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

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

希望对你有帮助。

【讨论】:

  • 这只是将太长的参数列表从 grep 转移到 for 语句。
  • 但那些不是真正的论据,它们是 bash 的内在。我刚刚创建了一个包含 1M 文件的文件夹并进行了测试: guido@solid:~/a$ ls * -bash: /bin/ls: Argument list too long guido@solid:~/a$ for i in *;做 ls $i;完成 1 10 100 ....
  • 如何绕过 xargs?
  • (for i in 1US*; do if grep -qi user@domain "$i"; then rm "$i"; fi; done)。这将检查 grep 的返回值以查看是否有匹配项,如果有则删除文件。还添加了 -q 选项来抑制 grep 的输出(我们不需要管道它,我们也不想要它)。如果您再次收到“参数过多”错误(我尝试处理一百万个文件没有问题,但以防万一)您最好使用find 删除文件。
【解决方案2】:

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

find -maxdepth 1 -name '1US*' -printf '%f\0' | xargs -0 grep -u user@domain | awk ...

【讨论】:

  • -print0-printf '%f\0' 的快捷方式。
【解决方案3】:

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

例如

# List the files that match
find /path/to/input/ -type f -exec grep -qiF spammer@spammy.com \{\} \; -print
# Once you're sure you've got it right
find /path/to/input/ -type f -exec grep -qiF spammer@spammy.com \{\} \; -delete

【讨论】:

    【解决方案4】:

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

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

    ls 1US* | xargs grep -i user@domain.com | awk -F: '{print $1}' | xargs rm
    

    但更简单的是:

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

    【讨论】:

      【解决方案5】:

      使用find 和循环代替xargs

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

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

      【讨论】:

        猜你喜欢
        • 2019-03-17
        • 2023-02-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-05-14
        • 1970-01-01
        • 2021-04-18
        • 2020-08-07
        相关资源
        最近更新 更多