我有一个包含大约1000个文件名的列表,可以在目录及其子目录下进行搜索。有数百个子目录超过1,000,000个文件。以下命令将运行find 1000次:
cat filelist.txt | while read f; do find /dir -name $f; done
有更快的方法吗?
答案 0 :(得分:13)
如果filelist.txt
每行只有一个文件名:
find /dir | grep -f <(sed 's@^@/@; s/$/$/; s/\([\.[\*]\|\]\)/\\\1/g' filelist.txt)
(-f
选项意味着grep搜索给定文件中的所有模式。)
<(sed 's@^@/@; s/$/$/; s/\([\.[\*]\|\]\)/\\\1/g' filelist.txt)
的说明:
<( ... )
被称为process subsitution,与$( ... )
有点相似。这种情况相当于(但使用流程替换更整洁,可能更快一点):
sed 's@^@/@; s/$/$/; s/\([\.[\*]\|\]\)/\\\1/g' filelist.txt > processed_filelist.txt
find /dir | grep -f processed_filelist.txt
对sed
的调用会在s@^@/@
的每一行上运行命令s/$/$/
,s/\([\.[\*]\|\]\)/\\\1/g
和filelist.txt
并将其打印出来。这些命令将文件名转换为可以更好地使用grep。
s@^@/@
表示在每个文件名之前加上/
。 (^
表示正则表达式中的“行首”)s/$/$/
表示在每个文件名的末尾添加$
。 (第一个$
表示“行尾”,第二个只是文字$
,然后由grep解释为“行尾”)。 这两个规则的组合意味着grep只会查找.../<filename>
之类的匹配项,因此a.txt
与./a.txt.backup
或./abba.txt
不匹配。
s/\([\.[\*]\|\]\)/\\\1/g
在每次出现\
.
[
或]
之前提出*
。 Grep使用正则表达式并且这些字符被认为是特殊的,但我们希望它们是简单的,所以我们需要转义它们(如果我们没有转义它们,那么像a.txt
这样的文件名将匹配像{{1}这样的文件})。
举个例子:
abtxt
Grep然后在搜索$ cat filelist.txt
file1.txt
file2.txt
blah[2012].txt
blah[2011].txt
lastfile
$ sed 's@^@/@; s/$/$/; s/\([\.[\*]\|\]\)/\\\1/g' filelist.txt
/file1\.txt$
/file2\.txt$
/blah\[2012\]\.txt$
/blah\[2011\]\.txt$
/lastfile$
的输出时将该输出的每一行用作模式。
答案 1 :(得分:3)
使用xargs(1)
for while循环可能比bash快一点。
喜欢这个
xargs -a filelist.txt -I filename find /dir -name filename
如果filelist.txt中的文件名包含空格,请注意,请阅读xargs(1)
manpage的描述部分中关于此问题的第二段。
基于某些假设的改进。例如,a.txt位于filelist.txt中,您可以确保/ dir中只有一个a.txt。然后,您可以告诉find(1)
在找到实例时提前退出。
xargs -a filelist.txt -I filename find /dir -name filename -print -quit
另一种解决方案。您可以预处理filelist.txt,使其成为这样的find(1)
参数列表。这将减少find(1)
次调用:
find /dir -name 'a.txt' -or -name 'b.txt' -or -name 'c.txt'
答案 2 :(得分:3)
如果filelist.txt
是普通列表:
$ find /dir | grep -F -f filelist.txt
如果filelist.txt
是模式列表:
$ find /dir | grep -f filelist.txt
答案 3 :(得分:0)
我不完全确定这里的问题,但是在尝试找到一种方法来发现13000个文件中有4个未能复制之后我来到了这个页面。
这两个答案都没有给我,所以我这样做了:
cp file-list file-list2
find dir/ >> file-list2
sort file-list2 | uniq -u
结果列出了我需要的4个文件。
想法是组合两个文件列表以确定唯一条目。
sort
用于制作彼此相邻的重复条目,这是uniq
过滤掉它们的唯一方式。