我有文件名列表,我想一一提供这些文件来查找命令,以便我可以获得路径。我已经使用 for 循环并使用 cat 命令获取变量中的所有文件名,然后将它们通过变量一一传递给 find 命令,但它不起作用。有人可以指导我吗?
for f in $(cat filelist.txt)
do
find /home/abc/ -type f -name "$f"
done;
我没有收到任何错误,但也没有得到输出,我也尝试将输出放入变量中,但没有运气。
答案1
如果您想查找名称为每行存储的文件中的任何一个的文件filelist.txt
,一种简单的方法是使用zsh
s globbing
:
names=( ${(f)"$(<filelist.txt)"} ) &&
(( $#names )) &&
print -rC1 -- /home/abc/**/${(~j[|])names}(D.)
至于为什么你的方法不起作用,虽然没有什么问题,但并不是立即显而易见的:
- 在 中
bash
,未加引号$(cat filelist.txt)
的内容对 的内容调用 split+glob (仅在 zsh 中拆分)filelist.txt
。使用默认值$IFS
(用于分割部分),它将在换行符上分割,也会在空格和制表符上分割。因此,如果其中有my file.txt
一行,它将查找调用的文件my
和调用的文件,file.txt
而不是调用的文件my file.txt
- 如果有一个文件
*
叫filelist.txt
文件,则全局部分会将其扩展为调用脚本的目录中的文件列表。 - 也
-name '*'
不会查找名为 的文件*
,但会报告每个文件,因为传递到的内容-name
被视为模式。您需要转义[
、?
和*
with\
以\
禁用通配符运算符。
现在,您的问题也可能是:
filelist.txt
是 MSDOS 文本格式,带有 CRLF 分隔符而不是 LF。你会运行dos2unix
它来修复它。- 您有文件路径
filelist.txt
(例如dir/file.txt
)。-name
仅匹配文件名,因此永远不会匹配该文件名。
在这里,您可以使用 GNU 代替循环xargs
:
xargs -rd'\n' -a filelist.txt -I NAME find /home/abc/ -name NAME -type f
但这仍然意味着要抓取每个文件名的整体/home/abc/
,这是低效的。
相反,你可以这样做:
xargs -rd'\n' -n200 -a <(sed 's/[*?\\[]/\\&/g' filelist.txt) sh -c '
for name do
set -- -o -name "$name"
shift
done
shift
find /home/abc/ \( "$@" \) -type f' sh
我们find /home/abc/ \( -name name1 -o -name name2... \) -type f
在一次调用中调用最多 200 个名称find
,这意味着/home/abc
.无论如何,不如zsh
只执行 1 的情况,但仍然好得多。
我们还使用sed
转义名称中的通配符。您也可以通过dos2unix
那里。
答案2
也试试
find -iname $(sed -z 's/\n$//; s/\n/ -o -iname /g' list.txt)
查找以 *nix 文本文件中不应该存在的字符sed -z
结尾的行\000
,因此它将整个文件加载到内存中。然后删除尾随<NL>
字符,并用剩余字符替换,-o -iname
以便find
获得一长串or
ed 文件名。