我正在尝试grep
在当前目录中保存40k个文件,但出现此错误。
for i in $(cat A01/genes.txt); do grep $i *.kaks; done > A01/A01.result.txt
-bash: /usr/bin/grep: Argument list too long
通常如何处理grep
数千个文件?
谢谢Upendra
这让大卫感到难过...
到目前为止,每个人都是错误的(anubhava除外)。
Shell脚本与任何其他编程语言都不一样,因为对行的大部分解释来自Shell在实际执行命令之前对它们进行插值的功能。
让我们做一些简单的事情:
$ set -x
$ ls
+ ls
bar.txt foo.txt fubar.log
$ echo The text files are *.txt
echo The text files are *.txt
> echo The text files are bar.txt foo.txt
The text files are bar.txt foo.txt
$ set +x
$
将set -x
让你看到的外壳实际上是如何插值的水珠,然后通过该回命令输入。的>
指向实际上正在由命令执行的行。
您会看到该echo
命令没有解释*
。相反,shell抓取*
并将其替换为匹配文件的名称。然后并且只有这样,该echo
命令才实际执行该命令。
当你有40K加的文件,你这样做grep *
,你就扩大这*
对那些40000个加文件的名称之前grep
甚至有执行的机会,而这也正是该错误消息的/ usr /斌/ grep的:参数列表过长是来自(哪里。
幸运的是,Unix可以解决这个难题:
$ find . -name "*.kaks" -type f -maxdepth 1 | xargs grep -f A01/genes.txt
该find . -name "*.kaks" -type f -maxdepth 1
会发现所有的*.kaks
文件,并且-depth 1
将只包括在当前目录下的文件。在-type f
确保你只拿起文件,而不是一个目录。
该find
命令通过管道将文件转换成的名称xargs
和xargs
将附加文件的名称grep -f A01/genes.txt
命令。但是,xargs
有套它的把戏。它知道命令行缓冲区有多长时间,并grep
在命令行缓冲区已满时执行,然后将另一个系列的文件传递给grep
。这样,grep
可能执行了三到十次(取决于命令行缓冲区的大小),并且所有文件都已使用。
不幸的是,xargs
使用空格作为文件名的分隔符。如果您的文件包含空格或制表符,则您将遇到麻烦xargs
。幸运的是,还有另一个解决方法:
$ find . -name "*.kaks" -type f -maxdepth 1 -print0 | xargs -0 grep -f A01/genes.txt
这-print0
将导致find
打印出文件名,这些文件名不是用换行符而是NUL字符分隔的。在-0
为参数xargs
告诉xargs
该文件分隔符不是空白,但NULL字符。因此,解决了该问题。
您也可以这样做:
$ find . -name "*.kaks" -type f -maxdepth 1 -exec grep -f A01/genes.txt {} \;
这将对grep
找到的每个文件执行,而不是对xargs
只能grep
在命令行中填充的所有文件执行操作,并且仅对其运行。这样做的好处是,它完全避免了外壳的干扰。但是,它可能会或可能不会效率较低。
有趣的是进行试验,看看哪种效率更高。您可以time
用来查看:
$ time find . -name "*.kaks" -type f -maxdepth 1 -exec grep -f A01/genes.txt {} \;
这将执行命令,然后告诉您花费了多长时间。与-exec
和一起尝试xargs
,看看哪个更快。让我们知道你发现了什么。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句