すべてのファイルをgzipからxzに動的に(再帰的に)変換するには?

すべてのファイルをgzipからxzに動的に(再帰的に)変換するには?

次のgzipファイルを含むディレクトリツリーがあります。

basedir/a/file.dat.gz
basedir/b/file.dat.gz
basedir/c/file.dat.gz
etc.

各ファイルをディスクに解凍せずに単一のコマンドを使用して、これらのファイルをすべてgzipからxzに変換する方法は?

ディスクに解凍するための簡単な2行のコードは次のとおりです。

find basedir/ -type f -name '*.dat.gz' -exec gzip -d {} \;
find basedir/ -type f -name '*.dat' -exec xz {} \;

最初のコマンドは短くすることができます。gunzip -r *

単一ファイルの場合、即時変換は簡単です(ただし、.gzファイルを置き換えるわけではありません)。

gzip -cd basedir/a/file.dat.gz | xz > basedir/a/file.dat.xz

gzipとxzは拡張自体を扱うので、次のように言いたいと思います。

gunzip -rc * > xz

find | xargs basename -s .gz { }少し見ましたが、うまくいく解決策が見つかりませんでした。

シェルスクリプトを書くこともできますが、簡単な解決策が必要だと思います。


編集する

答えてくれた皆さんに感謝します。私は皆が決して失敗しないコマンド™が好きであることを知っています。したがって、作業を単純にするには、次のようにします。

  • すべてのサブディレクトリには、数字、文字(単、äöü)、アンダースコア、マイナス記号のみが含まれています。
  • すべてのファイルの名前は file.dat[.n].gz で指定されます。 n は正の整数です。
  • どのディレクトリやファイルにも「.gz」はありません(最終ファイルのサフィックスを除く)。
  • これがこのディレクトリに含まれる唯一のコンテンツです。
  • 命名を制御し、必要に応じて制限できます。

単純なfind -exec ...ORを使用してls | xargs見つけたファイル名の「.gz」をすぐに「.xz」に置き換えることができるコマンドはありますか?その後、次のように書くことができます(医師)。

find basedir/ -type f -name '*.gz' -exec [ gzip -cd {} | xz > {replace .gz by .xz} \; ]

ベストアンサー1

find . -name '*.gz' -type f -exec bash -o pipefail -Cc '
  for file do
    gunzip < "$file" | xz > "${file%.gz}.xz" && rm -f "$file"
  done' bash {} +

-C既存のファイルの上書きやシンボリックリンクに従わないようにします。とは別に既存のファイルが非標準ファイルまたは非標準ファイルへのリンクである場合、afile.gzとaへのfile.xzシンボリックリンクがないとデータは失われません/dev/null。これを回避するには、実装されている機能のいくつかを使用して良い測定値を取得し、いくつかの競合状態を回避できますzsh-execdirfind

find . -name '*.gz' -type f -execdir zsh -o pipefail -c '
  zmodload zsh/system || exit
  for file do
    gunzip < "$file" | (
      sysopen -u 1 -w -o excl -- "${file%.gz}.xz" && xz) &&
      rm -f -- "$file"
  done' zsh {} +

または、再圧縮が失敗した場合はファイルをクリーンアップしますxz

find . -name '*.gz' -type f -execdir zsh -o pipefail -c '
  zmodload zsh/system || exit
  for file do
    sysopen -u 1 -w -o excl -- "${file%.gz}.xz" &&
      if gunzip < "$file" | xz; then
        rm -f -- "$file"
      else
        rm -f -- "${file%.gz}.xz"
      fi
  done' zsh {} +

短くしてこれらの潜在的な問題のいくつかを無視する準備ができている場合は、次のことがzshできます。

for f (./**/*.gz(D.)) {gunzip < $f | xz > $f:r.xz && rm -f $f}

おすすめ記事