我想对 Maildir 目录中的 500 个文件进行 grep 处理。我发出命令
grep MyPattern *
我收到错误消息:
bash: /usr/bin/grep: Argument list too long
所以我将文件列表存储在文件 MyFiles 中,并发出以下命令
for i in $(`cat MyFiles`); do echo $i; done
在执行 grep 之前,我想做一个 echo 来进行检查。但这给出了以下错误
bash: 1434361691.M617282P6399V0000000000000808I00000000000E16C1_23.ananda-linux,S=10055:2,S: command not found
其中 1434... 是目录中的第一个文件。
那么回到原来的问题。如何 grep 查找邮箱中的所有这些文件。我有更大的邮箱,包含 50000 封或更多电子邮件。
答案1
要求grep
自己通过从当前目录递归来构造文件列表:
grep -r MyPattern .
这与 不太一样*
,因为它会在子目录中搜索,但对于邮件目录,这通常是您想要的。
答案2
当 shell 执行外部命令时,在扩展任何文件名通配模式(例如 )之后,命令行的长度*
不得超过特定长度。
在您的情况下,grep 'PATTERN' *
扩展为 shell 无法执行的太长的命令。
在你的第二个例子中:
for i in $(`cat MyFiles`); do echo $i; done
您尝试迭代存储在 中的文件名MyFiles
,但语法非常错误。
$(`cat MyFiles`)
是相同的
$( $(cat MyFiles) )
这意味着 的内容MyFiles
将被解释为命令。这就是您收到command not found
错误的原因。
有多种方法可以解决此问题,但是循环遍历文件内容并不是一个好的方法。
斯蒂芬给出了一个很好的解决方案在他的回答中,另一种是,假设您当前的工作目录是 Maildir 文件夹,
find . -type f -exec grep 'PATTERN' {} +
这将grep
在大批量文件上执行几次尽可能。
这类似于
printf '%s\n' * | xargs grep 'PATTERN'
但该find
命令处理带有空格和嵌入换行符的文件名。
这里的命令printf
将每行输出一个文件名。它不会遇到同样的问题,因为grep 'PATTERN' *
它很可能是内置命令,因此不必由 shell 作为外部命令执行。
cat
您的循环解决方案也可以工作,但您可以简单地执行以下操作,而不是循环 的输出
for name in *; do
grep 'PATTERN' "$name"
done
这假设有仅常规文件在当前目录中。
为了确保您只处理邮件消息,您可以使用
for name in *,*; do
grep 'PATTERN' "$name" /dev/null
done
这会迭代至少包含一个逗号的名称。我还添加了/dev/null
强制grep
输出与给定模式匹配的文件的名称。如果您支持的话,您可以删除/dev/null
并改为使用-H
with 。grep
grep
这样的循环很慢,因为我们grep
对目录中的每个文件执行一次。