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。この特定のケースでは、結果が正しいことを確認するために stdout に出力するだけです。

問題は、ステートメントを通過できるものが何もないことです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

中括弧の展開では複数の異なるグロブが生成されますが、 の場合は@(..)1 つのグロブだけが生成されます。(つまり、*.{foo,bar}は と同じです*.foo *.bar) nullglobset の場合は一致しないグロブは問題になりませんが、failglobset を使用した場合は、一致しないグロブが 1 つあるだけで、コマンド全体が失敗します。

答え2

スクリプトには次のように書かれています:

  if grep -qF _AAC $file; then

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

_AAC代わりに、変数の展開の結果の文字列内でを検索する場合$file(つまり、ファイル名自体に _AAC が出現するかどうかを確認する場合)、 では次のようにbash記述する必要があります。

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

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

関連情報