web-dev-qa-db-ja.com

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

私は自分の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'を使う)

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

364
flip
find $directory -type f -name "*.in"

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

あなたのスクリプトはおそらく名前に.を持たないエントリに失敗し、$extensionを空にします。

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

example 現在のディレクトリとそのサブディレクトリにあるすべてのcsvファイルを検索する

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

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

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

(それは1つ少ないキーストロークです)。

57
Scott C Wilson

findを使わないで:

du -a $directory | awk '{print $2}' | grep '\.in$'
12
rtrn
  1. browsefolders ()の後に{がありません
  2. すべての$in$suffixであるべきです
  3. cutの行は、front.middle.extensionの中央部分だけを取得します。あなたは${varname%%pattern}とその友達についてあなたのシェルマニュアルを読むべきです。

私はあなたがこれをシェルスクリプティングの練習として行うと仮定します、さもなければ既に提案されたfind解決策は進むべき道です。

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

10
Jens

現在のディレクトリにあるすべてのpom.xmlファイルを見つけて印刷するには、次のようにします。

find . -name 'pom.xml' -print
6
Bharat Yadav

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

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

shopt -s extglob nullglob globstar

さて、あなたがする必要があるのは、あなたが以下のようにすることができる特定の拡張子のファイルを含むようにglob表現を形成することです。正しく引用され展開されると、特殊文字を含むファイル名はそのまま残り、シェルによる単語分割のために壊れることはないので、配列を使用します。

たとえば、再帰パス内のすべての*.csvファイルをリストするには

fileList=(**/*.csv)

オプション**はサブフォルダを再帰的に検索することであり、*.csvは言及された拡張子の任意のファイルを含めるためのglob展開です。実際のファイルを印刷するためには、

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

シェルスクリプトで使用する場合、配列を使用して適切な引用符で囲まれた展開を行うのが正しい方法ですが、対話的に使用する場合は、glob式を指定してlsを使用することができます。

ls -1 -- **/*.csv

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

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

これは否定的な結果もあるように非常にうまく拡大することができます。同じ構文で、globの結果を使用して特定の種類のファイルを除外することができます。上記の拡張子を持つファイル名を除外したいとします。

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

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

これらの拡張されたglobサポートはPOSIX bourneシェルでは利用できず、最近のバージョンのbashに純粋に固有のものです。ですから、POSIXシェルとbashシェルをまたいで実行されるスクリプトの移植性を考えているのであれば、このオプションは正しくありません。

3
Inian
find $directory -type f -name "*.in"|grep $substring
1
Sergiu
for file in "${LOCATION_VAR}"/*.Zip
do
  echo "$file"
done 
find "$PWD" -type f -name "*.in"
1
kip2