Как конвертировать все файлы из gzip в xz на лету (и рекурсивно)?

Вот один лайнер с использованием sed и awk :

sed '/^$/d' filename | awk '!a[$1]++' 

Комбинация grep и awk :

grep . filename | awk '!a[$1]++'

As @ cas предложил, вы также можете сделать это с помощью одной команды awk .

awk '!x[$1]++ && ! /^[[:blank:]]*$/' filename

7
09.09.2016, 12:04
4 ответа

Мне нравятся простые для циклов ...

for file in basedir/*/*.gz
do
    gzip -cd < "$file" | xz > "${file%%.gz}.xz"
done

... по крайней мере, если ваша структура каталогов регулярная и достаточно простая. Если вам нужно пройти на неизвестные глубины или выполнить дополнительные условия при выборе файла, вам все равно придется придерживаться find или аналогичного.

2
29.04.2021, 00:10
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 предотвращает перезапись существующего файла и не будет следовать символическим ссылкам , кроме , если исходящий файл является нестандартным файлом или ссылкой на нестандартный файл, поэтому вы не потеряете данные, если у вас нет, например, file.gz и file.xz , которые являются символической ссылкой на / dev / null . Чтобы защититься от этого, вы можете использовать вместо него zsh , а также использовать функцию -execdir некоторых реализаций find для хорошей меры и предотвращения некоторых состояний гонки:

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}
10
29.04.2021, 00:10

Вы можете сделать это с помощью find и parallel

parallel -0 'gzip -cd '{}' | xz > '{.}'.xz; rm '{}'' < <(find basedir -iname \*gz -print0)

Шаги завершены:

  • рекурсивный поиск всех файлов, заканчивающихся на gz (без учета регистра)
  • Stdin из подстановки процесса
  • параллельный gzip foo.gz | xz> {foo} .xz; rm foo.gz
    • {.} удаляет .gz из foo.gz (в моем понимании)
0
29.04.2021, 00:10
find basedir/ -type f -name '*.dat.gz'|while read -r line; do
 gzip -cd "$line" | xz > ${line%.gz}.xz
 rm "$line"
done
0
29.04.2021, 00:10

Теги

Похожие вопросы