Loop through all the files with a specific extension Ask Question

Loop through all the files with a specific extension Ask Question
for i in $(ls);do
    if [ $i = '*.java' ];then
        echo "I do something with the file $i"
    fi
done

I want to loop through each file in the current folder and check if it matches a specific extension. The code above doesn't work, do you know why?

ベストアンサー1

No fancy tricks needed:

for i in *.java; do
    [ -f "$i" ] || break
    ...
done

The guard ensures that if there are no matching files, the loop will exit without trying to process a non-existent file name *.java.

In bash (or shells supporting something similar), you can use the nullglob option to simply ignore a failed match and not enter the body of the loop.

shopt -s nullglob
for i in *.java; do
    ...
done

コメントでbreak-vs- の議論についてもう少し詳しく説明します。最初のループが 2 つのケースを区別しようとしているため、 と のどちらを使用するかは、範囲外であると考えます。continuebreakcontinue

  1. *.java一致するものがなかったため、リテラルテキストとして扱われます。
  2. *.java少なくとも 1 つの一致があり、その一致には という名前のエントリが含まれている可能性があります*.java

ケース 1 では、 forthcomingbreakの他の値がないため$ibreakおよび はcontinue同等になります (ただしbreak、ループが受動的に終了するのを待つのではなく、ループを終了している方が明確だと思います)。

ケース2では、可能な一致に対して必要なフィルタリングを行う必要があります。そのため、breakまたはの選択はどちらを選択するcontinueかよりも重要度が低くなります。テスト( -f-d-eなど) を に適用しますが$i、これは、そもそもループに「誤って」入ったかどうかを判断する間違った方法だと思います。

つまり、私は価値を検証する立場にはなりたくないのです$i まったくケース1とケース2では、値をどのように扱うかは、各ファイルのビジネスロジックと関係があり、選択するそもそも処理するファイルの種類。質問の中でどちらかの選択肢を表明するのではなく、そのロジックを個々のユーザーに任せたいと思います。


余談ですが、zshglob自体でこのようなフィルタリングを行う方法を提供しています。のみで終わる通常のファイル.java(一致しないパターンをリテラルテキストとしてではなくエラーとして扱うデフォルトの動作を無効にする)

for f in *.java(.N); do
  ...
done

上記の通り、あなたは保証されたループ本体に到達すると、 は$f通常のファイルの名前に展開されます。 は通常のファイルのみに.一致*.javaし、 はN一致に失敗した場合にエラーを生成する代わりに何も展開しません。

他にもこのようなglob 修飾子zshファイル名の展開に対してあらゆる種類のフィルタリングを実行します。( 's glob 展開により、 を使用する必要がなくなると冗談を言うのが好きですfind。)

おすすめ記事