特定の拡張子を持つファイルを再帰的に探します


437

私はbash(最新のUbuntu LTSリリース)を使用して、ディレクトリ内の特定の拡張子を持つすべてのファイルとそのサブディレクトリを検索しようとしています。

これはスクリプトファイルに記述されているものです。

#!/bin/bash

directory="/home/flip/Desktop"
suffix="in"

browsefolders ()
  for i in "$1"/*; 
  do
    echo "dir :$directory"
    echo "filename: $i"
    #   echo ${i#*.}
    extension=`echo "$i" | cut -d'.' -f2`
    echo "Erweiterung $extension"
    if     [ -f "$i" ]; then        

        if [ $extension == $suffix ]; then
            echo "$i ends with $in"

        else
            echo "$i does NOT end with $in"
        fi
    elif [ -d "$i" ]; then  
    browsefolders "$i"
    fi
  done
}
browsefolders  "$directory"

残念ながら、このスクリプトをターミナルで起動すると、次のように表示されます。

[: 29: in: unexpected operator

(の$extension代わりに'in'

ここで何が起こっていますか、エラーはどこにありますか?しかし、この中かっこ


2
エラーは「{」が欠落していることによるものです
shrewmouse

回答:


750
find $directory -type f -name "*.in"

その全体よりも少し短いです(そしてより安全です-ファイル名とディレクトリ名の空白を扱います)。

.名前にaが含まれていないエントリのスクリプトはおそらく失敗し、$extension空になります。


16
はい、findデフォルトで再帰的です。必要に応じて深さを制限できます(manページを参照)。
マット

1
見つかったすべてのファイルをjarファイルの引数として渡したいのですが。これはどのように実行できますか?
フリップ

8
@flip:それは別の質問です。新しい質問を投稿して、何をしたいか、これまでに試したことを正確に説明します。
マット

1つの小さな修正: "* .in"の代わりに '* .in'または\ *。inを使用してください。二重引用符はシェルの展開を妨げないためです。つまり、現在のディレクトリに拡張子が.inのファイルがある場合、スクリプトは正しく機能しません。
Shnatsel 2013

4
@Shnatsel:二重引用符はシェルの展開を防ぎます。やってみて。
マット

188
find {directory} -type f -name '*.extension'

例:csv現在のディレクトリとそのサブディレクトリ内のすべてのファイルを検索するには、次のコマンドを使用します。

find . -type f -name '*.csv'

60

私が使用する構文は、@ Mattが提案したものとは少し異なります。

find $directory -type f -name \*.in

(キーストロークが1つ少なくなります)。


1
Mattのスクリプトは、現在のディレクトリに.in拡張子のファイルがある場合も機能しませんが、あなたのファイルは機能します。stackoverflow.com/questions/5927369/…を
Shnatsel '19

4
@Shnatselこのコメント(そしてあなたのコメント)は明らかに間違っています。
gniourf_gniourf 2015

1
@gniourf_gniourfステートメントの参照を提供する必要があります。そうしないと、単に「いいえ、あなたは間違っている」と主張できます。しかし、実際にはあなたは正しい:gnu.org/software/bash/manual/html_node/Double-Quotes.html
Murmel

@ user1885518:スクリプトが失敗する例を提供するのは、スクリプトが機能しないと主張する人であるべきだと思います。これは、壊れたスクリプトがある場所にコメントを残すときに行うことです。通常、スペース、改行、グロブなどを含む引用符とファイル名に関するものであり、壊れた理由を具体的に説明します。
gniourf_gniourf 2016年

2
参照を提供することは常にディスカッションの良い方法です、それは誰が最初であったかに依存しません。彼はそうすべきです
Murmel

14

使用せずにfind

du -a $directory | awk '{print $2}' | grep '\.in$'

3
ここgrepでは本当に必要ありません。awk正規表現があり、その出力をパターンに一致する値に制限できます。
ケンスター2016年

この方法は、数百テラバイトを通過する場合に非常に役立ちます。Findコマンドの処理には時間がかかりすぎます。これはすぐに始まります。
Protonova 2017

1
awk|grepアンチパターンです。awkにgreppingを実行させます。
Jens

10
  1. あります{行方不明の後は、browsefolders ()
  2. すべて$in$suffix
  3. の行はcut、の中央部分のみを取得しますfront.middle.extension。シェルのマニュアルを読んでください${varname%%pattern}

私はこれをシェルスクリプトの練習として行うことを想定していますfind

スクリプトを実行せずに適切なシェル構文を確認するには、を使用しますsh -n scriptname



7

findここではコマンドを使用すると便利ですが、シェル自体に、サードパーティのツールなしでこの要件を達成するためのオプションが用意されています。のbashシェルを使用すると、再帰的なパスの下にファイル名を取得することができます使用して、拡張グロブサポートオプションを提供し、あなたがしたい拡張子を持つ一致します。

拡張オプションは以下extglobshoptオプションで設定する必要があります。オプションは-sサポートで有効になり、-uフラグで無効になります。さらに、いくつかのオプションをさらに使用することもできます。つまりnullglob、一致しないグロブを完全に一掃し、ゼロワードのセットに置き換えます。そしてglobstar、それはすべてのディレクトリを再帰的にすることを可能にします

shopt -s extglob nullglob globstar

あとは、グロブ式を作成して、以下のように特定の拡張子のファイルを含めるだけです。配列を使用してglobの結果を入力します。適切に引用されて展開されると、特殊文字を含むファイル名はそのまま残り、シェルによる単語分割のために壊れないからです。

たとえば*.csv、再帰パスにあるすべてのファイルを一覧表示するには

fileList=(**/*.csv)

オプション**は、サブフォルダーを再帰的に処理すること*.csvであり、言及された拡張子のファイルを含めるためのグロブ拡張です。実際のファイルを印刷するには、次のようにします

printf '%s\n' "${fileList[@]}"

シェルスクリプトで使用する場合は、配列を使用して適切に引用符で囲まれた展開を行うのが正しい方法ですが、インタラクティブに使用するには、次のようlsにグロブ式を使用するだけです

ls -1 -- **/*.csv

これは、複数のファイル、つまり複数の拡張子で終わるファイルに一致するように拡張できます(つまり、findコマンドに複数のフラグを追加するのと同様です)。たとえば、すべての再帰的な画像ファイルは拡張子のすなわち取得するために必要とする場合を考え*.gif*.pngそして*.jpg、ISにあなたが必要とするすべての

ls -1 -- **/+(*.jpg|*.gif|*.png)

これは、否定的な結果を得るために拡張することもできます。同じ構文で、グロブの結果を使用して特定のタイプのファイルを除外できます。上記の拡張子を持つファイル名を除外したい場合は、次のようにすることができます

excludeResults=()
excludeResults=(**/!(*.jpg|*.gif|*.png))
printf '%s\n' "${excludeResults[@]}"

コンストラクト!()は、内部にリストされているファイル拡張子を含まない否定演算|であり、グロブのOR一致を行うために拡張正規表現ライブラリで使用されるのと同じ代替演算子です。

これらの拡張globサポートはPOSIX bourneシェルでは利用できず、純粋にの最近のバージョンに固有であることに注意してくださいbash。したがって、POSIXとbashシェル間で実行されるスクリプトの移植性を検討している場合、このオプションは適切ではありません。


6

pom.xml現在のディレクトリにあるすべてのファイルを見つけて印刷するには、次のコマンドを使用できます。

find . -name 'pom.xml' -print


0
for file in "${LOCATION_VAR}"/*.zip
do
  echo "$file"
done 

1
このコードは質問に答えることがありますが、このコードが質問に答える理由および/または方法に関する追加のコンテキストを提供すると、その長期的な価値が向上します。
rollstuhlfahrer 2018
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.