2

У меня есть следующий код как часть сценария оболочки:

while [ $(ps -ef | awk '{print $2}' | grep -F "$CPPID") ]; do
    sleep 10
    awk -v "usbsize=$(/bin/df | grep -F $DEVICEMOUNTPOINTQ | awk '{print $3}')" -v "isosize=$(/bin/df | grep -F $ISOMOUNTPOINTQ | awk '{print $3}')" 'BEGIN { printf "%.1f", 100 * usbsize / isosize }' && echo "% copied..."
done

Это мониторинг cp выполняющий следующую операцию:

cp -a "$ISOMOUNTPOINT"/* "$DEVICEMOUNTPOINT"

И это работает нормально по большей части, пока

90.5% copied...
94.2% copied...
97.8% copied...
101.6% copied...
102.7% copied...

Почему это превышает 100% размера источника? Копия - из ISO-образа, смонтированного в петле, в раздел в формате NTFS на флэш-накопителе USB. Я предполагаю, что это, вероятно, вещь файловой системы?

Чего не хватает в моем примере, чтобы размеры соответствовали друг другу, чтобы при завершении cp он копировался на 100%, а не на 103%?

Благодарю.


Re: Баунти

Я назначу вознаграждение первому лицу, предложившему решение, аналогичное приведенному выше коду, которое соответствует следующим критериям:

  • Скрипт должен быть в состоянии обнаружить копирование в соотношении 1:1
  • Скрипт не должен отображать значение, превышающее 100%, однако...
  • Сценарий не должен просто ограничивать отображение на 100%, когда оно превышает его.

Если размер данных действительно отличается от источника к месту назначения по какой - то причине, то я хотел бы сценарий , который замечает это и по- прежнему отображает реальное соотношение скопированы.

3 ответа3

4

Первое, что я могу сделать, это то, что это будет в значительной степени зависеть от типа файлов в исходном каталоге. Я думаю, что вероятным виновником являются редкие файлы. Разреженный файл - это файл, где stat.st_size!= (stat.st_blksize * stat.st_blocks); то есть общий размер файла больше, чем количество блоков данных, связанных с индексом файла. Любые нераспределенные блоки считываются системными вызовами как блок нулей. Поэтому, когда вы используете cp (1) для разреженного файла, конечный файл будет содержать больше блоков (содержащих только нули), чем исходный файл. Команды du (1) и df (1) определяют количество блоков, а не размер файла (ов). Базовые файлы часто создаются как разреженные файлы, так как им может потребоваться отобразить память. Этот тип файла полезен для создания образов дисков, например, для создания диска виртуального хоста размером 15 ГБ. Было бы очень расточительно выделить все блоки во время создания; размер (st_size) может составлять 15 ГБ, но фактическое количество блоков может начинаться с 0.

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

2

Вы можете использовать rsync только в локальном режиме, когда у источника и получателя нет имени «:», поэтому он ведет себя как улучшенная команда копирования. С параметром progress он отображает что-то похожее на это (источник):

$ rsync -r -v --progress -e ssh root@remote-server:~/pictures /home/user/
receiving file list ...
366 files to consider
pictures/IMG_1142.jpg
 4400662 100%   32.21kB/s    0:02:13 (xfer#31, to-check=334/366)
pictures/IMG_1172.jpg
 2457600  71%   32.49kB/s    0:00:29

Поскольку это не дает общий процент, другое решение может быть использовать этот скрипт (источник):

#!/bin/sh
cp_p()
{
strace -q -ewrite cp -- "${1}" "${2}" 2>&1 \
  | awk '{
    count += $NF
        if (count % 10 == 0) {
           percent = count / total_size * 100
           printf "%3d%% [", percent
           for (i=0;i<=percent;i++)
              printf "="
           printf ">"
           for (i=percent;i<100;i++)
              printf " "
           printf "]\r"
        }
     }
     END { print "" }' total_size=$(stat -c '%s' "${1}") count=0
}

В бою:

% cp_p /mnt/raid/pub/iso/debian/debian-2.2r4potato-i386-netinst.iso /dev/null
76% [===========================================>                    ]

Вы также можете взглянуть на файлы перемещения с индикатором выполнения, который подробно описывает, как добавить в cp и mv ключ -g, чтобы показать прогресс.

1

Вот ваш код упрощен и сделан более читабельным:

while ps -p $CPPID > /dev/null
do
    sleep 10
    usbsize=$(/bin/df $DEVICEMOUNTPOINTQ | awk 'NR == 2 {print $3}')
    isosize=$(/bin/df $ISOMOUNTPOINTQ | awk 'NR == 2 {print $3}')
    awk -v "usbsize=$usbsize" -v "isosize=$isosize" 'BEGIN { printf "%.1f%% copied...\n", 100 * usbsize / isosize }'
done

Ваша последняя строка awk может быть заменена этими двумя:

    percent=$(echo "$usbsize / $isosize * 100" | bc -l)
    printf "%.1f%% copied...\n" $percent

Тогда вы можете сделать это непосредственно перед этим оператором printf :

if (( $(echo "$percent > 100" | bc) == 1 ))
then
    break
fi

и добавить wait $CPPID сразу после окончания цикла. Это остановит процесс печати после достижения 100%.

См. Управление процессами относительно надежности PID (они перерабатываются).

Вероятно, проблема, которую вы видите, связана с использованием "используемого" значения целевой файловой системы, а не с разницей текущего значения с начальным значением.

Попробуйте добавить строку , как это раньше while цикла:

startsize=$(/bin/df $DEVICEMOUNTPOINTQ | awk 'NR == 2 {print $3}')

и измените строку внутри цикла на:

usbsize=$(/bin/df $DEVICEMOUNTPOINTQ | awk -v "start=$startsize" 'NR == 2 {print $3 - start}')

Конечно, всего этого можно избежать, если вы используете rsync --progress вместо cp .

Редактировать:

Кроме того , попробуйте это в то while цикла , как показано выше , чтобы увидеть , что число используется при расчете является. Это может дать ключ к пониманию того, что происходит:

    awk -v "usbsize=$usbsize" -v "isosize=$isosize" 'BEGIN { printf "%d of %d, %.1f%% copied...\n", usbsize, isosize, 100 * usbsize / isosize }'

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