在大量纯文本文件的内容中搜索?

在大量纯文本文件的内容中搜索?

我的外部硬盘上有一个包含 1,242,276 个纯文本文件的目录。它们完全杂乱无章,文件名是无意义的数字。原因是因为不久前不小心清空了分区后,它们被某些恢复软件恢复了。

我现在在该目录下,想要在所有文件的内容中搜索单词“polyhedron”。我尝试过grep,但失败了:

$ grep polyhedron ./* 
bash: /bin/grep: Argument list too long

是不是因为该目录下的文件太多了?我还想搜索许多其他不同的关键字。我想知道我现在能做什么?

答案1

find . -type f -print0 | xargs -0 grep polyhedron

鉴于您可能想要执行一些操作,例如将具有匹配术语的文件复制到类似命名的文件夹中...

find . -type f -print0 | xargs -0 grep -l polyhedron | while read i; do cp "$i" ../polyhedron; done

如果您知道术语匹配之间没有重叠(也就是说,没有单个文件具有“多面体”和您想要组织的其他术语),那么您可以移动mv而不是复制cp

答案2

并不是文件太多,而是命令的参数列表grep太长。这是execve(2)系统调用对沿该调用传递的参数列表和环境变量列表的组合大小的限制。

ulimit -s在 Linux 上,自 2.6.23 起,它是一个管理限制,可以使用(还设置进程堆栈大小的限制)来提高或解除。所以

ulimit -s unlimited

可能适合你。

否则,解决方法(其中大部分已在其他答案中提到)包括拆分参数列表,使其符合该限制,或避免将文件列表传递给execve.

ls | xargs grep polyhedron

(可以,因为文件名只包含数字)

( xargs 负责分割列表并grep根据需要运行尽可能多的命令,这样execve就不会达到限制)。

find . -exec grep polyhedron {} +

相同,但这次find是分裂。

grep -r polyhedron .

(如果你的 grep 支持-r),这一次,只有几个字符的 3 个参数传递给grep,它会grep在内部构建文件列表,并且永远不会将其传递给 execve 系统调用。

有些贝壳有内置支持它。

对于内置的 shell grep,你不会遇到这个问题,因为内置的不是被处决通过execve系统调用。

通过 ksh93,您可以使用:

command -x grep polyhedron *

并将ksh93进行拆分。

zshzargs命令:

zargs * -- grep polyhedron

要搜索多个单词,您可以执行以下操作:

grep -e word1 -e word2 ...

或者

grep 'word1
word2
...' ...

或者将单词列表放入文件中,每行一个并使用

grep -f that-file ...

答案3

是不是因为该目录下的文件太多了?

是的。您使用通配符扩展。这就是您的所有文件名都扩展到命令行中。由于长度限制,此操作失败。要确定此限制,请尝试:

getconf ARG_MAX

我还想搜索许多其他不同的关键字。我想知道我现在能做什么?

您尝试过 grep 递归模式吗?

grep -r polyhedron .

正如其他答案所示,还有一些其他方法。本文还给出了该问题的一些背景以及如何规避此长度限制的更多示例。

我在这里复制了一些示例来给出一个想法:

使用find

find /nas/data/accounting/ -type f -exec ls -l {} \;

使用xargs

echo /nas/data/accounting/* | xargs ls -l

使用 while 循环:

find /nas/data/accounting/ -type f |
  while read file
  do
    mv /nas/data/accounting/$file /local/disk/
  done

答案4

你可以尝试:

find . -print0|xargs -0 grep 'term1\|term2'

xargsgrep将使用其默认的最大参数生成多个命令。如果您仍然收到“参数列表太长”错误,grep您可以--max-args使用xargs.
-print0使其-0使用以 null 结尾的文件名来处理带有空格的文件名。
您可以使用 搜索多个术语\|
有很多文件,因此您可能需要查看方法优化grep

相关内容