files.txt
いくつかのファイル名を含むというファイルがあります。ファイルを読み取り、aを実行して見つかったfind
ファイル名を返すコマンドがあります。その逆に行う方法が気になります。私が望むのは、見つからなかったファイル名を表示することです。
例:
$ 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
このループはファイルから一度に1つのファイル名を読み取り、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)