Как перенаправить стандартный вывод xz при выполнении команды tar | XZ?

Мне нужно использовать компрессор, такой как xz, для сжатия огромных архивов tar.

Я полностью осведомлен о предыдущих вопросах, таких как создание tar.xz в одной команде и использование многоядерности для сжатия / распаковки tar + gzip / bzip

Из них я обнаружил, что эта командная строка в основном работает:

tar -cvf - paths_to_archive | xz -1 -T0 -v > OUTPUT_FILE.tar.xz

Я использую решение для канала, потому что я абсолютно обязан передавать параметры в xz. В частности, xz очень сильно загружает процессор, поэтому я должен использовать -T0, чтобы использовать все доступные ядра. Вот почему я не использую другие возможности, такие как tar --use-compress-program или -J.

К сожалению, я действительно хочу записать все выходные данные tar и xz (т.е. неархивированные выходные данные) в файл журнала. В приведенном выше примере выход из системы всегда генерируется -v опции.

С командной строкой выше, тот вывод журнала теперь напечатан на моем терминале.

Итак, проблема в том, что когда вы используете каналы для соединения tar и xz, как указано выше, вы не можете завершить командную строку чем-то вроде

>Log_File  2>&1

из-за этого раньше

> OUTPUT_FILE.tar.xz

Есть ли решение?

Я попытался завернуть в подоболочку, как это

(tar -cvf - paths_to_archive | xz -1 -T0 -v > OUTPUT_FILE.tar.xz) >Log_File  2>&1

но это не сработало.

2 ответа

Решение

Нормальный стандартный вывод tar это тарбол и обычный вывод xz это сжатый файл Ни одна из этих вещей не является журналами, которые вы должны записывать. Все журналы, кроме самих выходных файлов, записываются исключительно в stderr для обоих процессов.

Следовательно, вам нужно только перенаправить stderr, и вы не должны перенаправлять stdout, если только вы не хотите, чтобы ваш выходной файл смешивался с журналированием.

{ tar -cvf - paths_to_archive | xz -1 -T0 -v > OUTPUT_FILE.tar.xz; } 2>Log_File

Кстати - если вам интересно, почему xz -v печатает больше контента, когда его вывод идет в TTY, ответ в этой строке message.c: progress_automatic флаг (говорящий xz, чтобы установить таймер для запуска SIGALRM - который он рассматривает как признак того, что статус должен быть напечатан - каждую секунду) устанавливается только тогда, когда isatty(STDERR_FILENO) правда. Таким образом, после того, как stderr был перенаправлен в файл, xz больше не печатает этот вывод вообще; проблема не в том, что он неправильно перенаправлен, а в том, что он больше не существует.

Вы можете, однако, отправить SIGALRM в xz каждую секунду из вашего собственного кода, если вы действительно так склонны:

{
  xz -1 -T0 -v > OUTPUT_FILE.tar.xz < <(tar -cvf - paths_to_archive) & xz_pid=$!
  while sleep 1; do
    kill -ALRM "$xz_pid" || break
  done
  wait "$xz_pid"
} 2>Log_File

(Код, который позволяет избежать округления времени, необходимого для xz выполнить до ближайшей секунды возможно, но оставлено как упражнение для читателя).

Первый -cvf - можно заменить на cv,

Но нормальный стандартный вывод tar cvf - это файл tar, который передается в xz, Не уверен, что я полностью понимаю, может быть, это:

tar cv paths | xz -1 -T0 > OUTPUT.tar.xz 2> LOG.stderr

или же

tar cv paths 2> LOG.stderr | xz -1 -T0 > OUTPUT.tar.xz

или же

tar cv paths 2> LOG.tar.stderr | xz -1 -T0 > OUTPUT.tar.xz 2> LOG.xz.stderr

Не уверен если -T0 Реализовано, какую версию xz вы используете? (Может быть, https://github.com/vasi/pixz стоит посмотреть поближе) pv программа, установленная с sudo apt-get install pv в некоторых системах лучше показать прогресс для труб, чем xz -v, Он скажет вам прогресс в процентах с ETA:

size=$(du -bc path1 path2 | tail -1 | awk '{print$1}')
tar c paths 2> LOG.stderr | pv -s$size | xz -1 -T0 > OUTPUT.tar.xz
Другие вопросы по тегам