Unix的find命令:从标准输入中列出文件列表

13

我在Linux和bash(或Cygwin和bash)上工作。

我有一个巨大的目录结构,必须在其中寻找一些需要的文件。

具体来说,我正在寻找这些文件(大约20个):

foo.c
bar.h
...
quux.txt

我知道它们在以.为根目录的某个子目录下。

我知道可以使用find . -name foo.c -print查找其中任意一个文件。这个命令需要几分钟才能执行完。

如何打印这些文件的名称和完整的目录名?我不想执行20个单独的find命令,那样太耗时间了。

我能否将文件列表从stdin或文件中传递给find?是否有其他命令可以满足我的要求?

我是否需要先使用循环或类似的方式组装一个带有-ofind命令行?

5个回答

12

如果你的目录结构很庞大但不经常发生变化,运行以下命令是个好选择:

cd /to/root/of/the/files
find . -type f -print > ../LIST_OF_FILES.txt #and sometimes handy the next one too
find . -type d -print > ../LIST_OF_DIRS.txt

在这样做之后,你可以使用grep、sed等工具非常快速地查找任何东西,并且仅在目录树改变时更新文件列表。(如果你没有locate的话,它是一个简单的替代品)

所以,

grep '/foo.c$' LIST_OF_FILES.txt #list all foo.c in the tree..

如果想要找到文件列表,你可以尝试以下方法:

fgrep -f wanted_file_list.txt < LIST_OF_FILES.txt

或直接使用find命令

find . type f -print | fgrep -f wanted_file_list.txt

-f 参数表示 fgrep 从文件中读取模式,因此您可以轻松地在输入中搜索多个模式...


4

您不需要运行20次find命令。

您可以使用多个文件名通配符构建一个单一的命令:

find . \( -name 'file1' -o -name 'file2' -o -name 'file3' \) -exec echo {} \;

-exec echo {} ; 不是必要的。 - akond
1
是的,谢谢,但我习惯于非GNU版本的“find”,所以我倾向于明确指出。如果将“echo”替换为例如“printf”,我们可以更好地控制输出。 - pavium
那么如果有20个这样的文件,难道没有其他选择,只能输入“-o -name” 20次吗?这并没有充分利用从stdin或文件中传输输入的管道功能。 - Sridhar Sarnobat

2

locate(1) 命令是否是一个可接受的答案?它每晚会构建索引,你可以快速查询这个索引:

$ time locate id_rsa
/home/sarnold/.ssh/id_rsa
/home/sarnold/.ssh/id_rsa.pub

real    0m0.779s
user    0m0.760s
sys 0m0.010s

我在36秒内放弃了在我的主目录下执行类似的find命令。 :)

如果夜间版本无法正常工作,您可以手动运行updatedb(8)程序,在运行locate(1)查询之前运行一次。 /etc/updatedb.conf (updatedb.conf(5))允许您选择要包含或排除的特定目录或文件系统类型。


这个原则上做了我想做的事情,为了得到我想要的东西,我可以用grep搜索我的目标目录,但夜间不起作用,而且我没有updatedb的权限。 - JXG
@JXG,不要忽略manpage的“EXAMPLES”部分 :) 要以非root用户身份创建私有的mlocate数据库,请运行 updatedb -l 0 -o db_file -U source_directory - sarnold
@JXG,啊,也许你的系统上安装的是slocate而不是mlocate。但愿它也能在没有root权限的情况下维护数据库。 - sarnold
当我使用你提供的示例时,它可以工作,但目录结构有很多符号链接指向各个地方。为整个文件系统构建数据库是不切实际的,更重要的是,我不知道哪些文件真正属于我,哪些属于别人但恰好具有相同的名称。 - JXG

1

一旦我将文件列表保存在数组中,使用循环构建查找命令?在这种情况下,最好使用哪个命令行? - JXG
你不需要将文件放入数组中;只需直接在数组中创建查找命令,然后调用它即可。 - Ignacio Vazquez-Abrams
那么,你具体要怎么做呢? - JXG

0
这是一种从标准输入中处理文件列表并组装您的(FreeBSD)查找命令以使用扩展正则表达式匹配(n1|n2|n3)的方法。
对于GNU查找,您可能需要使用以下选项之一来启用扩展正则表达式匹配:
- -regextype posix-egrep - -regextype posix-extended
echo '
foo\\.c
bar\\.h
quux\\.txt
' | xargs bash -c '
IFS="|"; 
find -E "$PWD" -type f -regex "^.*/($*)$" -print
echo find -E "$PWD" -type f -regex "^.*/($*)$" -print
' arg0

# note: "$*" uses the first character of the IFS variable as array item delimiter
(
IFS='|'
set -- 1 2 3 4 5
echo "$*"   # 1|2|3|4|5
)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接