2012-09-06 43 views
3

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

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

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

编辑:几个数字:

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

所有列在f中的文件确实存在于dir之下。

+0

因此,您的文件包含一个没有路径信息的文件名列表?你想如何处理多次出现的文件?我假设你要将整个目录树加载到内存中,以便快速完成此操作,因为重复扫描磁盘永远不会足够快,但是否可行取决于我们所谈论的大小。恐怕我不知道这样做的方式,但如果这是一个选项,用PHP或类似的方法做这件事会很微不足道? – Basic

+0

是的,只是文件名,结果必须包含所有可能的路径。可以将目录树加载到内存中,但我宁愿不使用PHP,因为它没有安装。尽管Perl或Python都可以。 – moatPylon

+2

+1使用'while read name ... done

回答

3

下面的一段python代码可以做到这一点。关键是运行find一次并将输出存储在散列表中,以提供从file_name到文件名路径列表的O(1)方法。

#!/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

为什么不使用'os.path.walk'和'os.path.basename(file_path)'? – Neil

+0

必须使用os.path.basename中的特殊字符。当'file_path'包含空格 – moatPylon

+0

4秒时失败,没有丢失文件。如果没有更短的内容出现,我会接受这个答案。 – moatPylon

1

我想这应该做的伎俩:

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

编辑:我想不出一个简单的方法,以前缀dir/*/到文件名列表,否则你可以只通过直接到xargs locate

+0

'locate'使用参数作为部分匹配,并打印绝对文件名。 'awk'{print“\\”$ 0}'f | xargs -d'\ n'找到-b | sed“s | $(pwd)/ || g”| grep^dir> d'可能会诀窍。 – moatPylon

+0

啊,是的,这些部分匹配,我的前缀想法没有这个问题,但它当然有没有找到'dir/$ file'的问题。 – Neil

2

尝试此perl的单行

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

1-创建散列映射的键是文件名:%H = {地图终日啃食; $ _ => 1} <>

2 - 定义一个递归子程序来遍历目录:子环R {}

2.1- recusive呼叫为目录:地图R($ _),如果-d $ p

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

2.3-打印如果散列映射包含文件名:打印 “$ P \ n” 个如果$ H {$ B}

3-呼叫R 2与路径当前目录: “” R

编辑:遍历隐藏目录

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

好而快,但由于某种原因它错过了几个文件 – moatPylon

+0

是否因为文件名可以包含像*这样的模式? –

+0

不是。事实上,我看不到缺少文件名的模式,我可以确认它们确实存在并被列出。 – moatPylon

0

根据目录树的百分比被认为是匹配的,它可能会更快找到文件,然后用grep出匹配(*)。的:

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

sed命令预先处理您的文件名列表为正则表达式,将只在路径的终点相匹配的全名。

+0

将此运行停留几分钟,完全没有输出。对每个组件进行定时显示,grep是罪魁祸首,并且,鉴于grep输出一找到就匹配的事实,我不认为这比我天真的方法更快。 – moatPylon

+0

太糟糕了。我甚至想到了一长串文件名,一个'grep'可能比许多对'find'的调用要快。 – chepner

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外壳顺应性(busybox的灰,嘘,等...)替换$列表操纵子串用的变体chepner's sed并用$(cat文件)替换$(<文件)

+0

chepner方法的问题不在于'find',而是'grep'的速度,它不是固定在你的版本中,它也包含两个问题:'find dir -type f'是没有理由重新实现,'grep“$ list”'会溢出命令行参数长度的限制 – moatPylon