セント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コマンドを実行して次のことをしたいと思います。
- foo.ext.gzファイルを探す
- gzファイルの内容の抽出そのGZファイルと同じディレクトリにあります
- 元の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
-k
bzip2
xz
gunzipkeep
1つの引数(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