El directorio copiado parece agrandarse en el destino

El directorio copiado parece agrandarse en el destino

Tengo el siguiente código como parte de un script de shell:

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

Este es el monitoreo cphaciendo la siguiente operación:

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

Y esto funciona bien en su mayor parte, hasta que

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

¿Por qué esto excede el 100% del tamaño de la fuente? La copia se realiza desde una ISO montada en bucle a una partición con formato NTFS en una unidad flash USB. ¿Supongo que esto probablemente sea una cuestión del sistema de archivos?

¿Qué le falta a mi ejemplo para que los tamaños coincidan, de modo que cuando cpesté completo se copie al 100%, no al 103%?

Gracias.


Re: Recompensa

Otorgaré la recompensa a la primera persona que produzca una solución similar al código anterior que cumpla con los siguientes criterios:

  • El script debe poder detectar copias en una proporción de 1:1.
  • El script no debe mostrar un valor superior al 100% copiado,sin embargo...
  • El script no debe simplemente limitar la visualización al 100% copiado cuando lo excede.

Si el tamaño de los datoshaceDe hecho, difieren del origen al destino por alguna razón, entonces me gustaría un script que note esto y aún muestre la proporción real copiada.

Respuesta1

Aquí está su código simplificado y hecho más legible:

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

Su última awklínea podría ser reemplazada por estas dos:

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

Entonces podrías hacer esto justo antes de esa printfdeclaración:

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

y agregue wait $CPPIDjusto después del final del whileciclo. Eso detendrá el progreso de la impresión una vez que se alcance el 100%.

VerGestión de procesocon respecto a la confiabilidad de los PID (se reciclan).

El problema que estás viendo probablemente se debe al uso del valor "usado" del sistema de archivos de destino en lugar deldiferenciaen el valor actual desde el valor inicial.

Intente agregar una línea como esta antes del whileciclo:

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

y cambie la línea dentro del bucle a:

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

Por supuesto, todo esto podría evitarse si utilizara rsync --progressen lugar de cp.

Editar:

Además, intente esto en el whilebucle como se muestra arriba para ver cuáles son los números que se utilizan en el cálculo. Eso podría proporcionar una pista de lo que está pasando:

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

Respuesta2

Mi primer paso es que dependería en gran medida del tipo de archivos en el directorio de origen. Creo que el posible culpable son los archivos escasos. Un archivo disperso es aquel en el que stat.st_size != (stat.st_blksize * stat.st_blocks); es decir, el tamaño total del archivo es mayor que el número de bloques de datos asociados con el inodo del archivo. Las llamadas al sistema leen los bloques no asignados como un bloque de ceros. Entonces, cuando usa cp(1) en un archivo disperso, el archivo de destino contendrá más bloques (que solo contienen ceros) que el archivo de origen. Los comandos du(1) y df(1) analizan el número de bloques, no el tamaño de los archivos. Los archivos principales a menudo se crean como archivos dispersos, ya que es posible que necesiten asignar memoria. Este tipo de archivo es útil para crear imágenes de disco, por ejemplo, crear una unidad de host virtual de 15 GB de tamaño. Sería un gran desperdicio asignar todos los bloques en el momento de la creación; el tamaño (st_size) podría ser de 15 GB, pero la cantidad real de bloques podría comenzar en 0.

Este es sólo un tipo de archivo que podría explotar al copiarlo. Sin saber qué tiene en su sistema de archivos, es difícil decir qué más podría estar haciendo eso.

Respuesta3

Puede usar rsync en modo solo local, donde tanto el origen como el destino no tienen un ':' en el nombre, de modo que se comporta como un comando de copia mejorado. Con el parámetro de progreso, muestra algo similar a esto (fuente) :

$ 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

Como esto no proporciona el porcentaje total, otra solución podría ser utilizar este script (fuente) :

#!/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
}

En acción:

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

También puedes echar un vistazo amover archivos con barra de progresoque detalla cómo agregar a cp y mv el modificador -g para mostrar el progreso.

información relacionada