grepはforループでファイル名を処理できません。

grepはforループでファイル名を処理できません。

Bashスクリプトを学びながら、forループに入れ子になったgrepを使用して結果をフィルタリングしようとしています。

sample filenames:
  this-file_AAC.txt
  this-other_file_AAAC.txt
  yep-a-file_AAC.nfo
  oops_another_one.reamde

スクリプトは次のとおりです。

shopt -s globstar nullglob dotglob
for file in ./**/*.{txt,reamde,nfo}; do
  printf "input: ${file}\n"
  if grep -qF _AAC $file; then
    printf "output: ${file}\n"
    # do stuff with $file
  fi
done

この特別な場合は、含まれているすべてのファイル_AACにジョブが適用され、結果が正しいことを確認するために標準出力に印刷するだけです。

問題は、どんなものもif文を超えることができないということです。それで私が知らないことが抜けましたね。働く唯一の事はこのprintf "input...減少です。

私は何を見逃していますか?

答え1

最後のファイル名部分に名前が付けられたすべてのファイルを一致させるには、.../something_AACxyzその部分をglobパターン/ワイルドカードに直接追加します。_AAC_AAC

for file in ./**/*_AAC*.{txt,reamde,nfo}; do

_AACファイル名を任意の部分に表示するには、Bashで次のようにします。

for file in ./**/*.{txt,reamde,nfo}; do
    if [[ $file == *_AAC* ]]; then
         echo "'$file' contains _AAC"
    else
         echo "'$file' has NO _AAC"
    fi
done

ここでは、globと一致するファイルも取得できますが_AAC


とにかく、Bashでは中括弧拡張を使用する代わりにパターンを有効にして上書きextglobすることもできます。@(...|...)

for file in ./**/*_AAC*.@(txt|reamde|nfo); do

中かっこ拡張は@(..)単一のglobですが、複数の異なるglobを作成します。 (つまり、*.{foo,bar}と同じ*.foo *.barnullglobsetを使用するときに一致しない項目は重要ではありませんが、setを使用するとfailglob一致しない項目が1つしかない場合でもコマンド全体が失敗します。

答え2

あなたのスクリプトは次のように言います:

  if grep -qF _AAC $file; then

これは、「指定されたファイルの内容に$fileリテラル文字列が含まれている場合_AAC...」ブロックの内容を実行することを意味しますthen

_AAC変数拡張で生成された文字列内で検索するには($file例:_AACがファイル名自体に表示されることを確認する)、次のように記述する必要がbashあります。

  if grep -qF _AAC <<< "$file"; then

あるいは、@roaimaが指摘したように、検索中のリテラル文字列をワイルドカードファイル仕様に含めることもできます。

関連情報