显示 while 循环中不匹配的文件名

显示 while 循环中不匹配的文件名

我有一个名为 的文件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)运算符进行不区分大小写的匹配来构建的。

相关内容