Dd

從文件中讀取確切字節數的 POSIX 方法是什麼?

  • November 10, 2020

剛剛遇到這個問題,並從選擇的答案中學到了很多東西:使用 dd 創建隨機數據並獲得“部分讀取警告”。現在警告後的數據真的是隨機的嗎?

不幸的是,建議的解決方案head -c是不可移植的。

對於堅持這dd是答案的人,請仔細閱讀連結的答案,其中詳細解釋了為什麼dd不能成為答案。另外,請注意:

$ dd bs=1000000 count=10 if=/dev/random of=random
dd: warning: partial read (89 bytes); suggest iflag=fullblock
0+10 records in
0+10 records out
143 bytes (143 B) copied, 99.3918 s, 0.0 kB/s
$ ls -l random ; du -kP random
-rw-rw-r-- 1 me me 143 Apr 22 19:19 random
4       random
$ pwd
/tmp

不幸的是,操作二進製文件的內容dd幾乎是 POSIX 中唯一的工具。儘管文本處理工具的大多數現代實現(cat, sed, awk, …)都可以操作二進製文件,但這不是 POSIX 所要求的:一些較舊的實現確實會阻塞空字節、輸入未由換行符終止或環境字元中的無效字節序列編碼。

安全使用是可能的,但很困難dd。我花費大量精力引導人們遠離它的原因是,有很多建議可以dd在它既無用也不安全的情況下進行推廣。

問題dd在於它的塊概念:它假設呼叫read返回一個塊;如果read返回較少的數據,你會得到一個部分塊,它會拋出類似skipcount關閉的東西。這是一個說明問題的範例,dd從傳輸數據相對較慢的管道讀取:

yes hello | while read line; do echo $line; done | dd ibs=4 count=1000 | wc -c

在沼澤標準 Linux(Debian jessie,Linux 核心 3.16,dd來自 GNU coreutils 8.23)上,我得到的字節數變化很大,從大約 3000 到幾乎 4000 不等。將輸入塊大小更改為 6 的除數,然後正如人們天真地期望的那樣,輸出始終為 4000 字節——輸入以dd6 字節的突發形式到達,只要一個塊不跨越多個突發,dd就可以讀取一個完整的塊。

這提出了一個解決方案:使用 1 的輸入塊大小。無論輸入是如何產生的,dd如果輸入塊大小為 1,則無法讀取部分塊。(這並不完全明顯:dd如果它被信號中斷,則可以讀取大小為 0 的塊 - 但如果它被中斷通過一個信號,read系統呼叫返回-1。read只有在非阻塞模式下打開文件時才可能返回0,在這種情況下read最好不要認為已經執行了。在阻塞模式下,read只有在文件末尾返回 0。)

dd ibs=1 count="$number_of_bytes"

這種方法的問題在於它可能會很慢(但不會慢得令人震驚:僅比head -c我的快速基準測試慢 4 倍)。

POSIX 定義了其他讀取二進制數據並將其轉換為文本格式的工具:(uuencode以歷史 uuencode 格式或 Base64 輸出),od(輸出八進製或十六進制轉儲)。兩者都不適合手頭的任務。uuencode可以通過 撤消uudecode,但是計算輸出中的字節數很麻煩,因為每行輸出的字節數沒有標準化。可以從 獲得明確定義的輸出od,但不幸的是,沒有 POSIX 工具可以反過來(它可以完成,但只能通過 sh 或 awk 中的慢循環來完成,這違背了這裡的目的)。

引用自:https://unix.stackexchange.com/questions/278443