我有以下程式碼作為 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
這是監視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
完成時是 100% 複製,而不是 103%?
謝謝。
回覆:賞金
我將向第一個產生類似上述程式碼且滿足以下條件的解決方案的人授予賞金:
- 該腳本必須能夠偵測 1:1 比例的複製
- 腳本顯示的值不得超過 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
一行可以替換為以下兩行:
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) 指令查看區塊數,而不是檔案大小。核心文件通常被創建為稀疏文件,因為它們可能需要映射記憶體。這種類型的檔案對於建立磁碟映像非常有用,例如建立大小為 15GB 的虛擬主機磁碟機。在創建時分配所有區塊將是非常浪費的;大小 (st_size) 可以是 15GB,但實際區塊數可以從 0 開始。
這只是複製時可能會爆炸的一種文件類型。如果不知道檔案系統中有什麼,就很難說還有什麼可能會這樣做。
答案3
您可以在僅本地模式下使用 rsync,其中來源和目標的名稱中都沒有“:”,因此它的行為類似於改進的複製命令。使用進度參數,它會顯示類似此的內容(來源):
$ 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 開關以顯示進度。