我有一个名为 的文件files.txt
,其中包含一些文件名。我有一个命令可以读取该文件并执行 afind
以返回它找到的文件名。我想知道如何做相反的事情,我想要的是显示它没有找到的文件名。
例子:
$ ls
file1 file2 file3 files.txt
$ cat files.txt
file1
file2
file3
file4
$ while read x; do (find . -iname "$x"); done < files.txt
./file1
./file2
./file3
在此示例中,我希望它显示file4
在结果中,因为该文件名位于 .txt 中,但文件夹中不存在。
答案1
使用grep
(对于当前文件夹中的文件,假设它们的名称不包含换行符)):
$ grep -v -i -F -x -f <(printf '%s\n' *) files.txt
file4
选项:
-v
反转匹配,选择不匹配的行-f
printf '%s\n' *
列出当前目录中的文件并用作grep
.-F
将模式解释为固定字符串(而不是正则表达式)-x
匹配整行-i
不区分大小写的匹配(就像你的-iname
)。
答案2
使用find
:
while IFS= read -r name; do
if [ -z "$(find . -iname "$name")" ]; then
printf 'Not found: %s\n' "$name"
fi
done <files.txt
此循环将从文件中一次读取一个文件名files.txt
,并在当前目录下的整个层次结构中搜索该名称,不区分大小写。如果未找到该名称(find
不输出任何内容),则会显示一条消息。
如果您想确保该find
命令仅查找常规文件(而不是目录等),请添加-type f
到该命令。
答案3
find
如果深度是一个目录,您可以这样做而不是使用:
while IFS= read -r file; do
[[ -f "${file}" ]] && echo "${file} exists" \
|| echo "$file doesn't exist";
done < files.txt
答案4
和zsh
:
set -o extendedglob # best in ~/.zshrc
files=(*(ND))
list=(${(f)"$(<files.txt)"})
not_found=(${list:#(#i)(${(~j[|])files})})
if (($#not_found)); then
echo "Not found:"
printf ' - %q\n' $not_found
fi
not_in_list=(${files:#(#i)(${(~j[|])list})})
if (($#not_in_list)); then
echo "Unexpected files (not in files.txt):"
printf ' - %q\n' $not_in_list
fi
它在当前目录(数组)中的文件列表和(数组)$files
中的文件列表之间进行不区分大小写的减法。files.txt
$list
zsh
确实有一个数组减法运算符(${array1:|array2}
),但如果我们想不区分大小写,就不能在这里使用它。
相反,我们使用${array:#pattern}
扩展为元素的运算符$array
除了那些匹配pattern
.
这里的模式是通过使用|
( j[|]
) 连接另一个数组的元素并使用extendedglob
(#i)
运算符进行不区分大小写的匹配来构建的。