Bashスクリプトを使用してサブディレクトリでtarアーカイブを検索する

Bashスクリプトを使用してサブディレクトリでtarアーカイブを検索する

多くの(> 5000)フォルダがあるディレクトリがあります。

folder1
folder2
folder3
...

これらすべてのフォルダには多くのサブディレクトリがあります。各フォルダの特定のサブディレクトリにtar.gzアーカイブがある可能性があります。フォルダにtar.gzアーカイブが含まれている場合、そのアーカイブは1つだけで、特定のサブディレクトリにあります。

たとえば、

folder1/foo/baz.tar.gz
folder2/bar/qux.tar.gz
folder3 [no tar.gz file in this folder]
...

次のタスクを実行するには、bashスクリプトを作成する必要があります。

  • tar.gz各フォルダを繰り返しながらアーカイブ(存在する場合)を見つけ、そのコンテンツを別のディレクトリ(すべての発見されたアーカイブに対して同じ)に抽出したいと思います。
  • 各アーカイブを見つけたら、アーカイブが保存されているパスとともに、アーカイブと同じディレクトリにさらにファイルを移動する必要がありtar.gzます。tar.gz

すべてのアーカイブを一覧表示できます。

find . -name "*tar.gz"

得られたコマンドを操作するのが最善の解決策なのか、それとも各ディレクトリを繰り返す方が良いのか疑問に思います。

最も最適化されたアプローチは何ですか?どうすればこれを行う必要がありますか?

ベストアンサー1

findデフォルトでは、オプションで単一のタスクまたはタスクのリストを実行できます-exec。それでは、untar各アーカイブをで実行するのはどうですかfind -exec?複雑なコマンドでは、この-exec関数を使用してシェルを呼び出し、-cシェルコマンドのオプションを使用して実行する実際のコマンドを渡すのが一般的です。たとえば(実際にこの実用的な例を実行するより簡単な方法がありますが、これはアイデアを示すためのものです):

-exec sh -c 'mv "$1" "~/$1"' sh {} ';'

これにより、見つかったファイルごとにシェルが起動し、そのファイルが$HOMEディレクトリに移動されます。見つかったファイル名をシェル位置引数として渡すために{}使用されます。そのため、$1シェルコマンドは代わりに$1使用されます{}。あなたの場合、このタイプの解決策は次のとおりです。

-exec sh -c 'tar xvf "$1" -C "$(dirname $1)"' sh {} ';' 

アイデアは、このイディオムがあなたが好むシェルのすべての機能を提供するということです。以内に注文するfind。 (はい、代わりにbashまたはを使用できます。ただし、読み込み速度がはるかに速く、多くのファイルで作業している場合は速度が速くなる可能性があることに注意してください。)zshshsh

何度も何度も何度も何度もやると予想される場合は、そしてマルチコアCPUがある場合は、2番目のオプションを検討するのが有利です。つまり、GNUパイプを介してファイルのリストをパイプし、すべてのコアで同時に作業を行うようにするparallelことです。untar初心者は次のことを試すことができます。

find . -name "*tar.gz" -type f -print0 |
  parallel -0 tar xvf {} -C {//}

dirname効率を上げるために上記の答えを使用すると、GNU Parallel自体がより効率的に実行できるため、外部コマンドを使用する必要はありません。これが{//}彼らがすることです。

警告:私はこれについての専門家ではなく、parallel実際の使用経験なしにこのオプションを提供しているので、これが正しいアプローチであるかどうか他の人がコメントを提示できると思います。

おすすめ記事