从存储在文件中的文件名列表中f
,找到每个文件名的相对路径并将dir
这个新列表输出到文件的最佳方法是什么p
?我目前正在使用以下内容:
while read name
do
find dir -type f -name "$name" >> p
done < f
这对于大型列表或大型目录树来说太慢了。
编辑:几个数字:
- 下目录数
dir
:1870 - 下的文件数
dir
:80622 - 中的文件名数
f
:73487
中列出的所有文件f
确实存在于dir
.
下面的一段 python 代码可以解决问题。关键是运行一次 find 并将输出存储在 hashmap 中,以提供从 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)
试试这个 perl 单行
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-创建一个哈希图,其键是文件名:%H=map{chomp;$_=>1}<>
2-定义一个递归子程序来遍历目录:sub R{}
2.1- 递归调用目录:map R($_), if -d$p
2.2-从路径中提取文件名: ($b=$p)=~s|.*/||
2.3- 如果 hashmap 包含文件名,则打印: print"$p\n" if$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
我认为这应该可以解决问题:
xargs locate -b < f | grep ^dir > p
编辑:我想不出一种简单的方法来dir/*/
为文件名列表添加前缀,否则你可以直接将它传递给xargs locate
.
根据目录树的百分比被认为是匹配的,找到每个文件可能会更快,然后 grep 出匹配的文件:
find "$dir" -type f | grep -f <( sed 's+\(.*\)+/\1$+' "$f" )
该sed
命令将您的文件名列表预处理为仅匹配路径末尾的全名的正则表达式。
这是使用 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 等...)将 $list 子字符串操作替换为 chepner 的 sed 的变体,并将 $(< file) 替换为 $(cat file)