任意のディレクトリにgzファイルを解凍し、解凍したファイルを同じディレクトリに保存する方法は?

任意のディレクトリにgzファイルを解凍し、解凍したファイルを同じディレクトリに保存する方法は?

セントOS 5.9

さまざまな任意のディレクトリにfoo.ext.gzファイルを含むサーバーがあります。

例:

  • /opt/fooapp/foosubdirectory/foo_randomnumber/blah/blah/foo.ext.gz
  • /opt/fooapp/foosubdirectory/foo_ Differentrandomnumber/blah/blah/foo.ext.gz
  • /opt/fooapp/foosubdirectory/foo_another その他の乱数/blah/blah/foo.ext.gz

bashコマンドを実行して次のことをしたいと思います。

  1. foo.ext.gzファイルを探す
  2. gzファイルの内容の抽出そのGZファイルと同じディレクトリにあります
  3. 元のgzファイルをそのまま残してください。

この操作を手動で実行するにはfind / -iname foo.ext.gz。次に、ファイルのあるディレクトリをコピーし、次のように入力します。

gunzip -c /opt/fooapp/foosubdirectory/foo_12345/blah/blah/foo.ext.gz  > /opt/fooapp/foosubdirectory/foo_12345/blah/blah/foo.ext

ここでの問題は、何十ものファイル/ディレクトリに対してこのプロセスを手動で実行する必要があることです。

xargsまたはforループを利用する方法はありますか?

答え1

の出力を解析できますが、findスペースなどを処理する必要があります。残念ながら保存する/フラグgunzipはありません(と同様に)。--keep-kbzip2xz

gunzipkeep1つの引数(gzipファイル)を使用して解凍する小さなスクリプトを作成したい場合は、$ PATHのどこかにスクリプトを置き、次のように呼び出します。

find /opt/fooapp/foosubdirectory -name "foo.ext.gz" -print0 | xargs -0 --norun-if-empty --max-args 1 gunzipkeep

スクリプトは次のとおりです。

#!/bin/bash
inname=$1
outname=${inname%.gz}

gunzip -c "$inname" > "$outname"

答え2

他の答えと同様に、ヘルパースクリプト(またはbash関数)を使用せずにこれを行うのは難しいですが、不可能ではありません。ここでは、-execdirオプションfindといくつかのパラメータ拡張が使用されますbash

find /opt/fooapp/foosubdirectory -name '*.gz' -execdir /bin/bash -c 'pwd ; echo ${0%.gz}; cp ${0} ${0%.gz}.tmp.gz ; gunzip ${0%.gz}.tmp.gz ; mv ${0%.gz}.tmp ${0%.gz}' {} \;

[編集] 注: この特定のパラメータ拡張には最新バージョンが必要ですbashが、一部の以前のバージョンではこの機能はありません。 V 3.2.xでテストしました。

[編集]注2:-execdir私が知っている限り、この表現はGNU find(および他の最新の実装)には存在しますが、以前の実装には存在しません。私はこれをGNU find v 4.2.xでテストしました。

読みやすさとコメントのために同じように書き直しました。

find /opt/fooapp/foosubdirectory 
     -name '*.gz'
     -execdir /bin/bash -c '_bash_command_string_ ' {} \;
# This ^ will run bash from the subdirectory containing the matched file

  _bash_command_string_  --> 
      pwd ;                       # we are working in this subdir 
      echo ${0%.gz};              # this is matched filename (minus final .gz)
      cp ${0} ${0%.gz}.tmp.gz ;   # copy the .gz file as .tmp.gz
      gunzip ${0%.gz}.tmp.gz ;    # gunzip the .tmp.gz as .tmp
      mv ${0%.gz}.tmp ${0%.gz}    # rename .tmp as matched filename (minus final .gz)

このソリューションは巧妙なソリューションとして興味深いですが、実際に使用するには複雑すぎる可能性があります。

バラよりBashリファレンス - シェルパラメータ拡張、探す ${parameter%word}

答え3

bash ≥4、shopt -s extglob再帰**/ディレクトリナビゲーションを実行します。 (これはディレクトリにシンボリックリンクを通過することに注意してください。zshでは特別な設定は必要ありません。シンボリックリンクではドロップダウンされませんが、**/そう***/なります。)その後、単純なループで十分です。

err=
for z in **/*.gz; do
  gunzip <"$z" >"${z%.gz}" &&
  touch -r "$z" "${z%.gz}" ||    # if you want to retain the file's modification time
  err=1
done
if [ -n "$err" ]; then echo >&1 'Watch out, there were errors!'; fi

POSIXのみを使用してshシェルから呼び出しますfind。エラー状態を抽出することはより困難です。コマンドがstderrから何を生成したかを確認してください。

find . -name '*.gz' -exec sh -c '
  for z do gunzip <"$z" >"${z%.gz}" && touch -r "$z" "${z%.gz}"; done
' _ {} +

答え4

find . -name \*.gz | parallel gzip -dc {} \> {.}
  • {.}拡張のない入力ラインです。
  • デフォルトの区切り文字は改行文字です。
find . -name \*.gz | while read f; do gzip -dc "$f" > "${f%.gz}"; done
  • 入力行がIFSの文字で始まるか終わるか、バックスラッシュを含めることができるかどうかIFS=を追加します。-r

関連情報