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 cp
haciendo 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 cp
esté 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 awk
lí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 printf
declaración:
if (( $(echo "$percent > 100" | bc) == 1 ))
then
break
fi
y agregue wait $CPPID
justo después del final del while
ciclo. 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 while
ciclo:
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 --progress
en lugar de cp
.
Editar:
Además, intente esto en el while
bucle 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.