114

У меня есть пара больших файлов, которые я хотел бы сжать. Я могу сделать это, например, с

tar cvfj big-files.tar.bz2 folder-with-big-files

Проблема в том, что я не вижу никакого прогресса, поэтому я понятия не имею, сколько времени это займет или что-то в этом роде. Используя v я могу по крайней мере увидеть, когда каждый файл будет завершен, но когда файлов мало и они большие, это не самое полезное.

Есть ли способ получить tar, чтобы показать более детальный прогресс? Например, процент выполнения или индикатор выполнения или оставшееся время или что-то еще. Либо для каждого отдельного файла, либо для всех, либо для обоих.

10 ответов10

86

Я предпочитаю oneliners, как это:

tar cf - /folder-with-big-files -P | pv -s $(du -sb /folder-with-big-files | awk '{print $1}') | gzip > big-files.tar.gz

Это будет иметь следующий результат:

4.69GB 0:04:50 [16.3MB/s] [==========================>        ] 78% ETA 0:01:21

Для OSX (из ответа Кендзи)

tar cf - /folder-with-big-files -P | pv -s $(($(du -sk /folder-with-big-files | awk '{print $1}') * 1024)) | gzip > big-files.tar.gz
73

Вы можете использовать PV для достижения этой цели. Чтобы правильно сообщить о прогрессе, pv должен знать, сколько байтов вы на него бросаете. Итак, первым шагом является вычисление размера (в килобайтах). Вы также можете полностью сбросить индикатор выполнения и просто позволить pv сказать вам, сколько байтов он видел; это сообщило бы, что «сделано так много и так быстро».

% SIZE=`du -sk folder-with-big-files | cut -f 1`

А потом:

% tar cvf - folder-with-big-files | pv -p -s ${SIZE}k | \ 
     bzip2 -c > big-files.tar.bz2
22

лучше прогресс бар ..

apt-get install pv dialog

(pv -n file.tgz | tar xzf - -C target_directory ) \
2>&1 | dialog --gauge "Extracting file..." 6 50

14

Проверьте параметры --checkpoint и --checkpoint-action на странице информации о tar (что касается моего дистрибутива, описание этих параметров не содержится на странице man → RTFI).

См. Https://www.gnu.org/software/tar/manual/html_section/tar_26.html.

С их помощью (и, возможно, функциональностью, чтобы написать свою собственную команду контрольной точки), вы можете рассчитать процент ...

6

Вдохновленный ответом помощника

Другой способ - использовать нативные параметры tar

FROMSIZE=`du -sk ${FROMPATH} | cut -f 1`;
CHECKPOINT=`echo ${FROMSIZE}/50 | bc`;
echo "Estimated: [==================================================]";
echo -n "Progess:   [";
tar -c --record-size=1K --checkpoint="${CHECKPOINT}" --checkpoint-action="ttyout=>" -f - "${FROMPATH}" | bzip2 > "${TOFILE}";
echo "]"

результат как

Estimated: [==================================================]
Progess:   [>>>>>>>>>>>>>>>>>>>>>>>

полный пример здесь

2

Использование только смолы

tar есть опция (начиная с v1.12) для вывода информации о состоянии сигналов, используя --totals=$SIGNO , например:

tar --totals=USR1 -czf output.tar input.file
Total bytes written: 6005319680 (5.6GiB, 23MiB/s)

Total bytes written: [...] информация печатается на каждом сигнале USR1, например:

pkill -SIGUSR1 tar

Источник:

2

Только что заметил комментарий о MacOS, и хотя я думаю, что решение от @akira (и pv) гораздо точнее, я подумал, что я поймал догадку и быстрый обходной путь в моей коробке MacOS с tar и отправил бы ей сигнал SIGINFO. Как ни странно, это сработало :), если вы работаете в BSD-подобной системе, это должно работать, но на Linux-боксе вам может потребоваться отправить SIGUSR1, и / или tar может работать не так.

Недостатком является то, что он предоставит вам только вывод (на стандартный вывод), показывающий, как далеко находится текущий файл, так как я предполагаю, что он понятия не имеет, насколько велик поток данных, который он получает.

Так что да, альтернативный подход - запускать tar и периодически отправлять SIGINFO в любое время, когда вы захотите узнать, как далеко он продвинулся. Как это сделать?

Специальный ручной подход

Если вы хотите иметь возможность проверять статус на специальной основе, вы можете нажать control-T (как упомянул Брайан Свифт) в соответствующем окне, которое отправит сигнал SIGINFO. Я считаю, что одна проблема заключается в том, что она отправит ее всей вашей цепочке, так что если вы делаете:

% tar cvf - folder-with-big-files | bzip2 -c > big-files.tar.bz2

Вы также увидите bzip2 отчет о его статусе вместе с tar:

a folder-with-big-files/big-file.imgload 0.79  cmd: bzip2 13325 running 
      14 0.27u 1.02s 

      adding folder-with-big-files/big-file.imgload (17760256 / 32311520)

Это хорошо работает , если вы просто хотите , чтобы проверить, что tar вы работаете застревает, или просто медленно. В этом случае вам, вероятно, не нужно слишком беспокоиться о проблемах форматирования, поскольку это только быстрая проверка.

Этакий автоматизированный подход

Если вы знаете, что это займет некоторое время, но вы хотите что-то вроде индикатора прогресса, альтернативой может быть запуск вашего процесса tar, а в другом терминале определить его PID, а затем выбросить его в скрипт, который просто несколько раз посылает сигнал через , Например, если у вас есть следующий скриптлет (и вызываете его как, скажем, script.sh PID-to-signal interval-to-signal-at):

#!/bin/sh

PID=$1
INTERVAL=$2
SIGNAL=29      # excuse the voodoo, bash gets the translation of SIGINFO, 
               # sh won't..

kill -0 $PID   # invoke a quick check to see if the PID is present AND that
               # you can access it..

echo "this process is $$, sending signal $SIGNAL to $PID every $INTERVAL s"
while [ $? -eq 0 ]; do
     sleep $INTERVAL;
     kill -$SIGNAL $PID;    # The kill signalling must be the last statement
                            # or else the $? conditional test won't work
done
echo "PID $PID no longer accessible, tar finished?"

Если вы вызываете его таким образом, поскольку вы нацеливаетесь только на tar вы получите более похожий результат

a folder-with-big-files/tinyfile.1
a folder-with-big-files/tinyfile.2
a folder-with-big-files/tinyfile.3
a folder-with-big-files/bigfile.1
adding folder-with-big-files/bigfile.1 (124612 / 94377241)
adding folder-with-big-files/bigfile.1 (723612 / 94377241)
...

что я признаю, это довольно мило.

И последнее, но не менее важное - мой сценарий довольно ржавый, поэтому, если кто-то захочет пойти и почистить / исправить / улучшить код, продолжайте в том же духе :)

2

Вдохновленный ответом Ноа Спурриера

function tar {
  local bf so
  so=${*: -1}
  case $(file "$so" | awk '{print$2}') in
  XZ) bf=$(xz -lv "$so" |
    perl -MPOSIX -ane '$.==11 && print ceil $F[5]/50688') ;;
  gzip) bf=$(gzip -l "$so" |
    perl -MPOSIX -ane '$.==2 && print ceil $F[1]/50688') ;;
  directory) bf=$(find "$so" -type f | xargs du -B512 --apparent-size |
    perl -MPOSIX -ane '$bk += $F[0]+1; END {print ceil $bk/100}') ;;
  esac
  command tar "$@" --blocking-factor=$bf \
    --checkpoint-action='ttyout=%u%\r' --checkpoint=1
}

Источник

1

Если вы знаете номер файла вместо общего размера всех из них:

альтернатива (менее точная, но подходящая) заключается в использовании опции -l и отправке в канале unix имен файлов вместо содержимого данных.

Давайте поместим 12345 файлов в mydir, команда:

[myhost@myuser mydir]$ tar cfvz ~/mytarfile.tgz .|pv -s 12345 -l > /dev/null 

вы можете узнать такое значение заранее (из-за вашего варианта использования) или использовать какую-то команду, например find+wc, чтобы обнаружить его:

[myhost@myuser mydir]$ find | wc -l
12345
0

Метод, основанный на tqdm:

tar -v -xf tarfile.tar -C TARGET_DIR | tqdm --total $(tar -tvf tarfile.tar | wc -l) > /dev/null

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .