我的外部硬盘驱动器上有一个包含 1,242,276 个纯文本文件的目录。它们完全没有组织,文件名是无意义的数字。原因是因为它们在不久前不小心清空了分区后被某些恢复软件恢复。
我现在在那个目录下,想在所有文件的内容中搜索“polyhedron”这个词。我试过了grep,但失败了:
$ grep polyhedron ./*
bash: /bin/grep: Argument list too long
Run Code Online (Sandbox Code Playgroud)
是不是因为那个目录下的文件太多了?我还想搜索许多其他不同的关键字。我想知道我现在能做什么?
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
如果您知道术语匹配之间没有重叠(也就是说,没有单个文件会包含 'polyhedron' 和您想要组织的其他一些术语),那么您可以 movemv而不是 copy cp。
不是文件太多,而是grep命令的参数列表太长。这是execve(2)系统调用对参数列表和通过该调用传递的环境变量列表的组合大小的限制。
在 Linux 上,从 2.6.23 开始,它是一个管理限制,可以使用ulimit -s(也设置进程堆栈大小的限制)来提高或解除。所以
ulimit -s unlimited
Run Code Online (Sandbox Code Playgroud)
可能对你有用。
否则,其他答案中已经提到的大多数解决方法包括拆分参数列表以使其符合该限制,或者避免将文件列表传递给execve.
ls | xargs grep polyhedron
Run Code Online (Sandbox Code Playgroud)
(确定只是因为文件名只包含数字)
(xargs 负责拆分列表并grep根据需要运行尽可能多的命令,以免execve达到限制)。
find . -exec grep polyhedron {} +
Run Code Online (Sandbox Code Playgroud)
相同,但这次find进行拆分。
grep -r polyhedron .
Run Code Online (Sandbox Code Playgroud)
(如果您的 grep 支持-r),这一次,只有几个字符的 3 个参数传递给grep,它grep在内部构建文件列表,并且从不将其传递给 execve 系统调用。
一些 shell内置了对它的支持。
使用grep内置的外壳程序,您不会遇到问题,因为内置程序不是通过系统调用执行的execve。
使用 ksh93,您可以使用:
command -x grep polyhedron *
Run Code Online (Sandbox Code Playgroud)
和ksh93会做分割。
zsh有zargs命令:
zargs * -- grep polyhedron
Run Code Online (Sandbox Code Playgroud)
要搜索多个单词,您可以执行以下操作:
grep -e word1 -e word2 ...
Run Code Online (Sandbox Code Playgroud)
或者
grep 'word1
word2
...' ...
Run Code Online (Sandbox Code Playgroud)
或者将单词列表放在一个文件中,每行一个并使用
grep -f that-file ...
Run Code Online (Sandbox Code Playgroud)
是不是因为那个目录下的文件太多了?
是的。您使用通配符扩展。那就是您的所有文件名都扩展到命令行中。这将失败,因为存在长度限制。要确定此限制,请尝试:
getconf ARG_MAX
Run Code Online (Sandbox Code Playgroud)
我还想搜索许多其他不同的关键字。我想知道我现在能做什么?
您是否尝试过 grep 递归模式?
grep -r polyhedron .
Run Code Online (Sandbox Code Playgroud)
正如其他答案所示,还有一些其他方法。本文还提供了有关该问题的一些背景知识以及如何规避此长度限制的更多示例。
我在这里复制了一些示例以提供一个想法:
使用find:
find /nas/data/accounting/ -type f -exec ls -l {} \;
Run Code Online (Sandbox Code Playgroud)
使用xargs:
echo /nas/data/accounting/* | xargs ls -l
Run Code Online (Sandbox Code Playgroud)
使用while循环:
find /nas/data/accounting/ -type f |
while read file
do
mv /nas/data/accounting/$file /local/disk/
done
Run Code Online (Sandbox Code Playgroud)