O diretório copiado parece ficar maior no destino

2

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?

Qual é o meu exemplo em falta para fazer com que os tamanhos correspondam, de modo que, quando cp for concluído, ele seja 100% copiado e não 103%?

Obrigado.

Re: Recompensa

Eu recompensarei a recompensa à primeira pessoa para produzir uma solução semelhante ao código acima que atenda aos seguintes critérios:

  • O script deve ser capaz de detectar a cópia na proporção de 1: 1
  • O script não deve exibir um valor acima de 100% copiado, no entanto ...
  • O script não deve limitar a exibição a 100% quando for excedido.

Se o tamanho dos dados não realmente diferir da origem para o destino por algum motivo, então eu gostaria de um script que perceba isso e ainda exiba a taxa real copiada.

    
por Matthieu Cartier 31.01.2011 / 17:53

3 respostas

1

Aqui está o 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 linha awk pode ser substituída por estas duas:

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

Então, você poderia fazer isso logo antes da declaração printf :

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

e adicione wait $CPPID logo após o final do loop while . Isso interromperá o progresso da impressão quando 100% for alcançado.

Veja Gerenciamento de processos sobre a 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 da diferença no valor atual do valor inicial.

Tente adicionar uma linha como essa antes do loop while :

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 evitado se você usou rsync --progress em vez de cp .

Editar:

Além disso, tente isso no loop while como 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 }'
    
por 31.01.2011 / 18:44
4

Meu primeiro passo é que dependeria em grande parte do tipo de arquivos no diretório de origem. Eu acho que o provável culpado são arquivos esparsos. Um arquivo esparso é aquele em que stat.st_size! = (Stat.st_blksize * stat.st_blocks); ou seja, o tamanho total 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) que o arquivo de origem. Os comandos du (1) e df (1) observam o número de blocos, não o tamanho do (s) arquivo (s). Os arquivos principais geralmente são criados como arquivos esparsos, já que podem precisar mapear a memória. Esse tipo de arquivo é útil para criar imagens de disco, por exemplo, a criação de uma unidade de host virtual de tamanho 15 GB. Seria muito dispendioso alocar todos os blocos no momento da criação; o tamanho (st_size) poderia ser de 15GB, mas o número real de blocos poderia 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 fazendo isso.

    
por 31.01.2011 / 19:05
2

Você pode usar o rsync no modo somente local, em que tanto a origem quanto o destino não têm um ':' no nome, para que ele se comporte como um comando de cópia aprimorado. Com o parâmetro progress, ele exibe algo semelhante a isso ( source ):

$ 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 dá a porcentagem total, outra solução pode ser usar esse 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 olhada em mover arquivos com a barra de progresso que detalha como adicionar ao cp e mv a opção -g para mostrar o progresso.

    
por 04.02.2011 / 21:45