シェル スクリプトの一部として次のコードがあります。
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 から USB フラッシュ ドライブ上の NTFS 形式のパーティションに行われます。これはおそらくファイル システムの問題だと思います。
私の例では、サイズを一致させて、cp
完了時に 103% ではなく 100% コピーされるようにするために何が欠けているのでしょうか?
ありがとう。
Re: 賞金
以下の基準を満たす、上記のコードに類似したソリューションを最初に作成した人に賞金を授与します。
- スクリプトは1:1の比率でコピーを検出できなければならない
- スクリプトは100%を超えるコピーされた値を表示してはならない。しかし...
- スクリプトは、コピーされた量が 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
行は次の 2 つに置き換えることができます。
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% に達すると印刷の進行が停止します。
見るプロセス管理PID の信頼性に関して (リサイクルされます)。
発生している問題は、おそらく、宛先ファイルシステムの「使用済み」値ではなく、違い開始値から現在の値まで。
ループの前に次のような行を追加してみてください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 GB の仮想ホストのドライブを作成する場合などです。作成時にすべてのブロックを割り当てるのは非常に無駄です。サイズ (st_size) は 15GB になる場合がありますが、実際のブロック数は 0 から始まる可能性があります。
これは、コピーすると爆発する可能性のあるファイルの 1 つのタイプにすぎません。ファイルシステムに何があるかがわからないため、他に何が爆発を引き起こしているかを判断するのは困難です。
答え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 スイッチを追加する方法を詳しく説明します。