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


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

現在のフォルダー内の各ファイルをループして、特定の拡張子と一致するかどうかを確認したいと思います。上記のコードは機能しません、なぜでしょうか?


4
どうfor i in $(ls *.java); do echo "do something with file $i"; doneですか?
講演者2013年

ifステートメントを修正する方法はありませんか?
AR89

1
$iリテラル文字列「* .java」と比較しています。ここではパターン展開は行われません。
chepner 2013年

ifステートメントを修正するには、if [[ $i == *.java ]]; then..を使用します(二重の[[]]と引用符で囲まれていない* .javaに注意してください)。
そのほかの男

2
解析しないls -@chepnerの回答を受け入れる
glenn jackman 2013年

回答:


201

特別なトリックは必要ありません:

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

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

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

5
最も簡単な方法は、別のパターンを追加することですfor i in *.java *.cpp; do。で拡張パターンを有効にbashしているshopt -s extglob場合は、を書くことができますfor i in *.@(java|cpp); do
chepner

8
実際に任意のファイルと一致する場合は、そうなります。shopt -s nullglob一致しないパターンが文字どおりに処理されるのではなく、空のシーケンスに展開されるように使用する必要があります。
chepner 2015

1
@zygimantusはい、必要です。現在のディレクトリがスクリプトの実行元である限り、そうする必要があります。目的のディレクトリにいない場合はcdforループを開始する前にそのディレクトリに移動する必要があります
danielsdesk

1
@pukシェルオプションによって異なります。デフォルトでは、一致しないパターンはリテラル文字列として扱われます。あなたは設定することができnullglob、それが空のシーケンス、またはセットとして扱われているようにfailglob、それはエラーとして扱われているし。(両方を設定した場合は、failglob優先されます。)
chepner 2017

3
@chepner誰かがコピーして貼り付けて機能しない場合があるので、専門家ではない人が回答にこれを示すと便利です。完璧な例は、重要な機能を実行する前にすべての「.jpg」ファイルを「 .png」に変換する人です
puk

13

正解は@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

ext代わりに変数を使用すると.javaどうなりますか?
AR89、2013年

13

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

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

代わりのfind . -name "*.java" -type f -exec echo \{\} \; 出力のmisparsing避けるためにfind
ウムラウト

1
そうでない場合は、少なくとも"$i"ループ内で引用する必要があります。
Tripleee

2
ファイルの名前に空白が含まれている場合、これは機能しません。
codeforester

1
@codeforesterまさにその問題があり、次の回答の方法を使用して修正しました:askubuntu.com/a/343753/551184
fsinisi90

7

:ループで終わるすべてのファイルを通じて.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

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

上記のコードは機能しません、なぜでしょうか?

はい!

優れた記事テスト、[と[の違いは何ですか[?]は、他の違いの中で、あなたが使用できないことを詳細に説明するexpression matchingか、pattern matchingtest(の省略形であるコマンド[

機能新しいテスト[[古いテスト[例

パターンマッチング=(または==)(使用不可)[[$ name = a *]] || echo "名前が 'a'で始まっていません:$ name"

正規表現=〜(使用不可)[[$(date)=〜^ Fri \ ... \ 13]] && echo「13日は金曜日です!」
マッチング

これがスクリプトが失敗する理由です。OPが[[構文を使用した回答([コマンドと同じ数のプラットフォームでサポートされないという欠点がある)に関心がある場合は、回答を編集してそれを含めることができます。

編集:表として回答のデータをフォーマットする方法のヒントは役に立ちます!


2

@chepnerが彼のコメントで言っているように、あなたは$ iを固定文字列と比較しています。

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

例えば:

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

=〜の右側の正規表現は、左側の演算子の値に対してテストされ、引用符で囲まないでください(引用符はエラーにならず、固定文字列と比較されるため、失敗する可能性が高いです。)

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


ext代わりに変数を使用すると.javaどうなりますか?
AR89 2013年

1
ack、正規表現は必要ありません:if [[ $i == *.java ]]またはif [[ $i == *.$ext ]]。しかし、lsを解析しないでください
glenn jackman 2013年

1

このソリューションは非常に便利であることがわかりました。次の-orオプションを使用しますfind

find . -name \*.tex -or -name "*.png" -or -name "*.pdf"

これは、拡張子を持つファイルを検索しますtexpngpdf

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.