Eu tenho o seguinte código como parte de um 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
Isso está monitorando cp
fazendo a seguinte operação:
cp -a "$ISOMOUNTPOINT"/* "$DEVICEMOUNTPOINT"
E isso funciona bem na maior parte, até
90.5% copied...
94.2% copied...
97.8% copied...
101.6% copied...
102.7% copied...
Por que isso excede 100% do tamanho da fonte? A cópia é de um ISO montado em loop para uma partição formatada em NTFS em uma unidade flash USB. Eu estou supondo que isso é provavelmente uma coisa do sistema de arquivos?
O que falta no meu exemplo para combinar os tamanhos, para que quando cp
concluído seja 100% copiado e não 103%?
Obrigado.
Re: Recompensa
Concederei a recompensa à primeira pessoa que produzir uma solução semelhante ao código acima que atenda aos seguintes critérios:
- O script deve ser capaz de detectar cópias na proporção de 1:1
- O script não deve exibir um valor superior a 100% copiado,no entanto...
- O script não deve simplesmente limitar a exibição a 100% copiada quando exceder esse limite.
Se o tamanho dos dadosfazde fato diferem de origem para destino por algum motivo, então eu gostaria de um script que percebesse isso e ainda exibisse a proporção real copiada.
Responder1
Aqui está seu código simplificado e mais legível:
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
Sua última awk
linha poderia ser substituída por estas duas:
percent=$(echo "$usbsize / $isosize * 100" | bc -l)
printf "%.1f%% copied...\n" $percent
Então você poderia fazer isso antes dessa printf
declaração:
if (( $(echo "$percent > 100" | bc) == 1 ))
then
break
fi
e adicione wait $CPPID
logo após o final do while
loop. Isso interromperá a impressão do progresso quando 100% for alcançado.
VerGerenciamento de processosem relação à confiabilidade dos PIDs (eles são reciclados).
O problema que você está vendo provavelmente se deve ao uso do valor "usado" do sistema de arquivos de destino em vez do valordiferençano valor atual a partir do valor inicial.
Tente adicionar uma linha como esta antes do while
loop:
startsize=$(/bin/df $DEVICEMOUNTPOINTQ | awk 'NR == 2 {print $3}')
e mude a linha dentro do loop para:
usbsize=$(/bin/df $DEVICEMOUNTPOINTQ | awk -v "start=$startsize" 'NR == 2 {print $3 - start}')
É claro que tudo isso pode ser evitável se você usar rsync --progress
em vez de cp
.
Editar:
Além disso, tente fazer isso no while
loop conforme mostrado acima para ver quais são os números usados no cálculo. Isso pode fornecer uma pista sobre o que está acontecendo:
awk -v "usbsize=$usbsize" -v "isosize=$isosize" 'BEGIN { printf "%d of %d, %.1f%% copied...\n", usbsize, isosize, 100 * usbsize / isosize }'
Responder2
A primeira coisa é que isso dependeria muito do tipo de arquivo no diretório de origem. Eu pensaria que o provável culpado são arquivos esparsos. Um arquivo esparso é aquele onde stat.st_size != (stat.st_blksize * stat.st_blocks); isto é, o tamanho geral do arquivo é maior que o número de blocos de dados associados ao inode do arquivo. Quaisquer blocos não alocados são lidos como um bloco de zeros pelas chamadas do sistema. Portanto, quando você usa cp(1) em um arquivo esparso, o arquivo de destino conterá mais blocos (contendo apenas zeros) do que o arquivo de origem. Os comandos du(1) e df(1) analisam o número de blocos, não o tamanho do(s) arquivo(s). Os arquivos principais geralmente são criados como arquivos esparsos, pois podem precisar mapear a memória. Este tipo de arquivo é útil para criar imagens de disco, por exemplo, criar uma unidade de host virtual com tamanho de 15 GB. Seria um grande desperdício alocar todos os blocos no momento da criação; o tamanho (st_size) pode ser 15 GB, mas o número real de blocos pode começar em 0.
Este é apenas um tipo de arquivo que pode explodir quando copiado. Sem saber o que você tem em seu sistema de arquivos, é difícil dizer o que mais pode estar causando isso.
Responder3
Você pode usar o rsync no modo somente local, onde a origem e o destino não possuem um ':' no nome, para que ele se comporte como um comando de cópia aprimorado. Com o parâmetro progress, exibe algo semelhante a isto (fonte) :
$ 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 isso não fornece a porcentagem total, outra solução pode ser usar este script (fonte) :
#!/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
}
Em ação:
% cp_p /mnt/raid/pub/iso/debian/debian-2.2r4potato-i386-netinst.iso /dev/null
76% [===========================================> ]
Você também pode dar uma olhadamover arquivos com barra de progressoque detalha como adicionar a cp e mv a opção -g para mostrar o progresso.