web-dev-qa-db-ja.com

特定の拡張子を持つすべてのファイルをループします

for i in $(ls);do
    if [ $i = '*.Java' ];then
        echo "I do something with the file $i"
    fi
done

現在のフォルダー内の各ファイルをループし、特定の拡張子と一致するかどうかを確認します。上記のコードは機能しませんが、その理由はわかりますか?

95
AR89

派手なトリックは必要ありません:

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

ガードは、一致するファイルがない場合、存在しないファイル名*.Javaを処理しようとせずにループが終了することを保証します。 bash(または同様のものをサポートするシェル)では、nullglobオプションを使用して、失敗した一致を単に無視し、ループの本体を入力することはできません。

shopt -s nullglob
for i in *.Java; do
    ...
done
174
chepner

正解は@chepnerの

EXT=Java
for i in *.${EXT}; do
    ...
done

ただし、ファイル名に特定の拡張子があるかどうかを確認するための小さなコツを次に示します。

EXT=Java
for i in *; do
    if [ "${i}" != "${i%.${EXT}}" ];then
        echo "I do something with the file $i"
    fi
done
13
umläute

サブフォルダーを再帰的に追加し、

for i in `find . -name "*.Java" -type f`; do
    echo "$i"
done
9
luismartingil

.img.bin.txtサフィックスで終わるすべてのファイルをループし、ファイル名を出力します。

for i in *.img *.bin *.txt;
do
  echo "$i"
done

または、再帰的な方法で(すべてのサブディレクトリでも検索):

for i in `find . -type f -name "*.img" -o -name "*.bin" -o -name "*.txt"`;
do
  echo "$i"
done
3
Benny

@chepnerがコメントで述べているように、$ iを固定文字列と比較しています。

状況を拡張および修正するには、正規表現演算子=〜で[[]]を使用する必要があります

例えば:

for i in $(ls);do
    if [[ $i =~ .*\.Java$ ]];then
        echo "I want to do something with the file $i"
    fi
done

=〜の右側の正規表現は、左辺演算子の値に対してテストされ、引用符で囲まれるべきではありません(引用符で囲まれたものはエラーになりませんが、固定文字列と比較されるため、失敗する可能性が高いです」

しかし、グロブを使用した上記の@chepnerの答えは、はるかに効率的なメカニズムです。

2
peteches

ファイルをループする正しい方法に関する他の回答に同意します。しかし、OPは尋ねました:

上記のコードは機能しませんが、その理由はわかりますか?

はい!

優れた記事 testと[[[?]]の違いは何ですか? では、testコマンド内でexpression matchingまたはpattern matchingを使用することはできないことを詳細に説明しています(これは[の省略形です)

 
 Feature new test [[old test [Example 
 
 Pattern matching =(or ==)(not available)[[$ name = a *]] || echo "名前が 'a'で始まらない:$ name" 
 
正規表現=〜(使用不可)[[$(date)=〜^ Fri\...\13] ] && echo "13日の金曜日です!" 
 matching 

これが、スクリプトが失敗する理由です。 OPが[[構文([コマンドほど多くのプラットフォームでサポートされていないというデメリットがある)の回答に興味がある場合は、回答を編集してそれを含めます。 。

編集:回答内のデータをテーブルとしてフォーマットする方法についてのヒントは参考になります!

2
user000001