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

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

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

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 для отображения прогресса.

Связанный контент