再帰 bash 関数を呼び出すと分割エラーが発生します。

再帰 bash 関数を呼び出すと分割エラーが発生します。

以下の3つに示すように、zipファイル内に入れ子になったファイルを含む数千のzipファイルを含む数百の複数のフォルダがあります。

start tree structure
012016/
├── 2016-01
│   └── 2016-01
│       ├── build
│       ├── DOC
│       │   ├── WONWA1
│       │   │   ├── WO1NWA1
│       │   │   │   ├── WO2016000001NWA1.xml
│       │   │   ├── WO1NWA1.zip
│       │   │   ├── WO2NWA1
│       │   │   │   ├── WO2016000002NWA1_tr.xml
│       │   │   ├── WO2NWA1.zip
└── 2016-01.zip

end tree structure

以下にフォルダと内容を再帰的に確認する簡単なスクリプトを作成しました。 zipファイルが見つかったら、内容を抽出し、抽出したフォルダの内容を確認します。

以下のスクリプトを実行しようとすると:

recurse() {
    for i in "$1"/*;
    do
        currentItem="$i"
        extension="${currentItem##*.}"

        if [ -d "$i" ]; then
            #echo "dir: $i"
            recurse "$i"
        elif [ -f "$i" ];   then
            #echo "file: $i"
            #echo "ext: $extension"

            [[ ${extension} = +(sh|xslt|dtd|log|txt) ]] && break

            extractionDirectory=$(dirname $currentItem)/$(basename -s .zip $currentItem )

            [[ ${extension} = "zip" ]] && unzip -uq $currentItem -d "${extractionDirectory}"

            recurse ${extractionDirectory}
        fi
    done }
    recurse $PWD

ただし、上記のスクリプトを実行すると、次のエラーが発生します。

分割エラー(コアダンプ)

ベストアンサー1

分割エラーはいくつかの理由で発生する可能性があります。最も一般的な下位レベルの原因は、未定義のメモリアドレスにアクセスしようとしているプロセス、つまり無効なポインタの逆参照です。これは通常プログラムのバグです。

ここではシェルプログラムを実行しています。シェルは高度なプログラミング言語であり、ポインタがないため、スクリプトで誤ったポインタの逆参照が発生することはありません。

多くのプログラムはスペースが限られています。コールスタックスタックサイズを超えたために発生した分割エラーです。ほとんどの場合、スタックサイズの制限は合理的な量のデータに対して十分ですが、無限再帰によりスタックが破損する可能性があります。

Bashでは、関数呼び出しの無限再帰は実際に分割エラーを引き起こす可能性があります。 (dashとmkshも同様です。kshとzshはよりスマートで、シェルレベルで最大関数呼び出しのネスト深さを適用するため、セグフォルトは発生しません。)


スクリプトにいくつかのエラーがあります。あなたをいじめるのは、通常のファイルの場合は、常にrecursezipファイルに対してのみ呼び出したい場合は常に最後に呼び出すことです。

またはを意味するときは使用しないでください&&。あなたが意味するものを書くのがより明確です。あいまいさを通じた簡潔さは良い考えではなく、ここではあなたを悩ませます。||if

if [[ ${extension} = "zip" ]]; then
  unzip -uq $currentItem -d "${extractionDirectory}"
  recurse ${extractionDirectory}
fi

もう一つのエラーは、あなたが欠けているということです変数の置換は二重引用符で囲まれています。したがって、プログラムは何よりもスペースを含むファイル名をブロックします。変数置換を省略する必要があることを知らない限り、必ず二重引用符を使用してください。

basenameとを呼び出す代わりに、パラメータ拡張を使用してくださいdirname。特別な場合(たとえば、で始まるファイル名など-)を処理する方が簡単で迅速です。

私が見つけたもう一つのバグは、パターンが+(sh|xslt|dtd|log|txt)明らかに意味することです@(sh|xslt|dtd|log|txt)(これらの拡張子と一致するshshものではありませんdtdtxtshdtd)。

caseこれは一般的なファイル状況です。上記のエラーは修正され、明確にするために書き直されました。

case "$extension" in
  sh|xslt|dtd|log|txt) break;;
  zip)
    extractionDirectory=$"{currentItem%.zip}"
    unzip -uq "$currentItem" -d "${extractionDirectory}"
    recurse "${extractionDirectory}"
esac

ロジックを確認したり、コードをテストしていません。書く方法が複雑に見えます。

find -type f -name '*.zip' -exec sh -c 'unzip -uq "$0" -d "${0%.zip}"' {} \;

おすすめ記事