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

Dag*_*ang 7 linux bash shell

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

cat filelist.txt | while read f; do find /dir -name $f; done
Run Code Online (Sandbox Code Playgroud)

有更快的方法吗?

huo*_*uon 13

如果filelist.txt每行有一个文件名:

find /dir | grep -f <(sed 's@^@/@; s/$/$/; s/\([\.[\*]\|\]\)/\\\1/g' filelist.txt)
Run Code Online (Sandbox Code Playgroud)

(该-f选项意味着grep搜索给定文件中的所有模式.)

说明<(sed 's@^@/@; s/$/$/; s/\([\.[\*]\|\]\)/\\\1/g' filelist.txt):

<( ... )被称为进程替换,并且有点类似于$( ... ).这种情况相当于(但使用流程替换更整洁,可能更快一些):

sed 's@^@/@; s/$/$/; s/\([\.[\*]\|\]\)/\\\1/g' filelist.txt > processed_filelist.txt
find /dir | grep -f processed_filelist.txt
Run Code Online (Sandbox Code Playgroud)

调用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匹配文件一样abtxt).

举个例子:

$ 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$
Run Code Online (Sandbox Code Playgroud)

然后Grep在搜索输出时使用该输出的每一行作为模式find.


小智 5

如果filelist.txt是简单列表:

$ find /dir | grep -F -f filelist.txt
Run Code Online (Sandbox Code Playgroud)

如果filelist.txt是模式列表:

$ find /dir | grep -f filelist.txt
Run Code Online (Sandbox Code Playgroud)