Shell:在目录下的列表中查找文件

时间:2012-03-31 05:47:44

标签: linux bash shell

我有一个包含大约1000个文件名的列表,可以在目录及其子目录下进行搜索。有数百个子目录超过1,000,000个文件。以下命令将运行find 1000次:

cat filelist.txt | while read f; do find /dir -name $f; done

有更快的方法吗?

4 个答案:

答案 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/gfilelist.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过滤掉它们的唯一方式。