У меня есть следующий код как часть скрипта оболочки:
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% копирования при его превышении.
Если размер данныхделаетдействительно по какой-то причине отличаются от источника к месту назначения, то мне нужен скрипт, который замечает это и по-прежнему отображает фактическое скопированное соотношение.
решение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%.
ВидетьУправление процессомотносительно надежности ПИД (они перерабатываются).
Проблема, которую вы видите, вероятно, связана с использованием значения «used» целевой файловой системы, а неразницав текущем значении от начального значения.
Попробуйте добавить перед циклом такую строку 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 }'
решение2
Мой первый довод заключается в том, что это во многом зависит от типа файлов в исходном каталоге. Я думаю, что вероятным виновником являются разреженные файлы. Разреженный файл — это тот, где stat.st_size != (stat.st_blksize * stat.st_blocks); то есть общий размер файла больше, чем количество блоков данных, связанных с inode файла. Любые нераспределенные блоки считываются системными вызовами как блок нулей. Поэтому, когда вы используете cp(1) для разреженного файла, целевой файл будет содержать больше блоков (содержащих только нули), чем исходный файл. Команды du(1) и df(1) смотрят на количество блоков, а не на размер файла(ов). Файлы ядра часто создаются как разреженные файлы, поскольку им может потребоваться отображение памяти. Этот тип файла полезен для создания образов дисков, например, создания диска виртуального хоста размером 15 ГБ. Было бы очень расточительно выделять все блоки во время создания; размер (st_size) может составлять 15 ГБ, но фактическое количество блоков может начинаться с 0.
Это всего лишь один тип файла, который может взорваться при копировании. Не зная, что у вас в файловой системе, трудно сказать, что еще может это делать.
решение3
Вы можете использовать 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 для отображения прогресса.