Скопированный каталог становится больше в месте назначения

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%, когда оно превышает его.

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

Матье Картье
источник
неясно, что вы хотите в итоге: просто скопируйте файлы с помощью командной строки и дайте прогресс? Как это относится к названию вашего вопроса?
Акира
У меня есть рабочая установка, которая уже дает прогресс, однако он превышает 100% скопированного. Я хочу знать, почему это так, и как достичь одной из целей, указанных в конце.
Матье Картье

Ответы:

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сразу после окончания whileцикла. Это остановит процесс печати после достижения 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 }'
Деннис Уильямсон
источник
Спасибо за помощь, однако, он должен быть переносимым - bc даже не установлен в моей системе по умолчанию, поэтому я склонен сказать, что не могу считать его «переносимым». Однако я постараюсь внести изменения, которые вы перечислили, через несколько минут (в течение нескольких минут). Спасибо! :)
Матье Картье
@neurolysis: bcеще одна опция для выполнения математических операций с плавающей точкой, которая может привести к более коротким командам. Я просто считал само собой разумеющимся, что это вездесуще. AWK подходит для этой цели.
Деннис Уильямсон
Это, кажется, печатает нан% для меня. Вы можете воспроизвести это?
Матье Картье
@neurolysis: Какая часть делает это?
Деннис Уильямсон
1
@neurolysis: что делать /bin/df $DEVICEMOUNTPOINTQи /bin/df $ISOMOUNTPOINTQвыводить? Это одна строка заголовка, за которой следует что-то вроде /dev/xxx 1111 2222 3333 44% /mountpoint? Если вы добавите echo "[$DEVICEMOUNTPOINTQ] [$ISOMOUNTPOINTQ]"перед командой AWK, что она выводит? Кстати, у меня есть опечатка в этом фрагменте. В конце есть двойная кавычка. Попробуйте удалить это.
Деннис Уильямсон
4

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

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

Arcege
источник
Файловая система буквально чиста (сценарий оболочки также удаляет MBR, включая таблицу разделов, и устанавливает новый раздел NTFS с нуля). Спасибо за информацию!
Матье Картье
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, чтобы показать прогресс.

harrymc
источник
Я рассмотрел использование strace, но накладные расходы смешны.
Матье Картье
Я не уверен насчет накладных расходов. Это хороший сценарий, возможно, стоит попробовать.
Harrymc
Просто невозможно использовать что-то, что, по-видимому, приводит к замедлению копирования примерно на 30%. Но спасибо.
Матье Картье
Стандартная заставка для красного лица: почему бы просто не ограничить свой сценарий процентом до 99,9%, пока он не закончится? Никто никогда не поймет, почему он немного колеблется на 99,9.
harrymc