从文件名列表中查找路径的有效方法

时间:2012-09-06 11:31:00

标签: bash shell find

从存储在文件f中的文件名列表中,找到dir下每个文件名的相对路径的最佳方法是什么,将此新列表输出到文件p ?我目前正在使用以下内容:

while read name
do
    find dir -type f -name "$name" >> p
done < f

对于大型列表或大型目录树来说太慢了。

编辑:一些数字:

  • dir下的目录数:1870
  • dir下的文件数:80622
  • f中的文件名数:73487

f中列出的所有文件都存在于dir下。

5 个答案:

答案 0 :(得分:3)

下面的python代码可以解决这个问题。关键是运行find一次并将输出存储在hashmap中,以提供O(1)方式从file_name获取文件名的路径列表。

#!/usr/bin/env python
import os

file_names = open("f").readlines()
file_paths = os.popen("find . -type f").readlines()
file_names_to_paths = {}
for file_path in file_paths:
    file_name = os.popen("basename "+file_path).read()
    if file_name not in file_names_to_paths:
        file_names_to_paths[file_name] = [file_path]
    else:
        file_names_to_paths[file_name].append(file_path) # duplicate file

out_file = open("p", "w")
for file_name in file_names:
    if file_names_to_paths.has_key(file_name):
        for path in file_names_to_paths[file_name]:
            out_file.write(path)

答案 1 :(得分:2)

试试这个perl one-liner

perl -e '%H=map{chomp;$_=>1}<>;sub R{my($p)=@_;map R($_),<$p/*> if -d$p;($b=$p)=~s|.*/||;print"$p\n" if$H{$b}}R"."' f

1-创建一个键值为文件名的hashmap:%H = map {chomp; $ _ =&gt; 1}&lt;&gt;

2-定义遍历目录的递归子例程:sub R {}

2.1-目录的重复调用:map R($ _),if -d $ p

2.2-从路径中提取文件名:($ b = $ p)=〜s |。* / ||

2.3-打印如果hashmap包含文件名:print“$ p \ n”如果$ H {$ b}

3-用路径当前目录调用R:R“。”

编辑:遍历隐藏目录(。*)

perl -e '%H=map{chomp;$_=>1}<>;sub R{my($p)=@_;map R($_),grep !m|/\.\.?$|,<$p/.* $p/*> if -d$p;($b=$p)=~s|.*/||;print"$p\n" if$H{$b}}R"."' f

答案 2 :(得分:1)

我认为这应该可以解决问题:

xargs locate -b < f | grep ^dir > p

编辑:我想不出一种简单的方法可以将dir/*/添加到文件名列表中,否则您可以直接将其传递给xargs locate。< / p>

答案 3 :(得分:0)

根据目录树被视为匹配的百分比,找到每个文件可能会更快,然后查找匹配的文件:

find "$dir" -type f | grep -f <( sed 's+\(.*\)+/\1$+' "$f" )

sed命令将您的文件名列表预处理为正则表达式,该表达式只匹配路径末尾的全名。

答案 4 :(得分:0)

这是使用bash和grep

的替代方法
#!/bin/bash

flist(){
for x in "$1"/*; do #*/ for markup
[ -d "$x" ] && flist $x || echo "$x"
done
}

dir=/etc #the directory you are searching
list=$(< myfiles) #the file with file names

#format the list for grep
list="/${list//
/\$\|/}"

flist "$dir" | grep "$list"

...如果你需要完整的posix shell兼容性(busybox ash,hush等...)用chepner的sed变种替换$ list子串操作,用$(cat file)替换$(&lt; file)