多くの(> 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
またはを使用できます。ただし、読み込み速度がはるかに速く、多くのファイルで作業している場合は速度が速くなる可能性があることに注意してください。)zsh
sh
sh
何度も何度も何度も何度もやると予想される場合は、そしてマルチコアCPUがある場合は、2番目のオプションを検討するのが有利です。つまり、GNUパイプを介してファイルのリストをパイプし、すべてのコアで同時に作業を行うようにするparallel
ことです。untar
初心者は次のことを試すことができます。
find . -name "*tar.gz" -type f -print0 |
parallel -0 tar xvf {} -C {//}
dirname
効率を上げるために上記の答えを使用すると、GNU Parallel自体がより効率的に実行できるため、外部コマンドを使用する必要はありません。これが{//}
彼らがすることです。
警告:私はこれについての専門家ではなく、parallel
実際の使用経験なしにこのオプションを提供しているので、これが正しいアプローチであるかどうか他の人がコメントを提示できると思います。
答え2
findコマンドを使用して、解凍できるスクリプトにtarballパスを渡すことができます(まだテストしていません)。
$ cat script
#!/bin/bash --
tarball="${1}"
dir="$(dirname ${tarball})"
tar xvf "${tarball}" -C "${dir}"
次に find を使ってスクリプトを呼び出します。
$ find . -type f -name '*.tar.gz' -exec ./script "{}" \;
またはfindコマンドで(クイックテスト):
find . -type f -name '*.tar.gz' -exec sh -c 'dir="$(dirname ''"{}"'')"; tar xvf "{}" -C "${dir}"' \;