使用 dd 創建隨機資料並獲得“部分讀取警告”。現在警告後的數據真的是隨機的嗎?

使用 dd 創建隨機資料並獲得“部分讀取警告”。現在警告後的數據真的是隨機的嗎?

我創建了一個 1TB 文件,其中包含隨機資料dd if=/dev/urandom of=file bs=1M count=1000000。現在我檢查kill -SIGUSR1 <PID>進度並得到以下資訊:

691581+0 Datensätze ein
691580+0 Datensätze aus
725174190080 Bytes (725 GB) kopiert, 86256,9 s, 8,4 MB/s
800950+1 Datensätze ein
800950+0 Datensätze aus
839856947200 Bytes (840 GB) kopiert, 99429,5 s, 8,4 MB/s
dd: warning: partial read (809620 bytes); suggest iflag=fullblock
803432+1 Datensätze ein
803431+1 Datensätze aus
842459273876 Bytes (842 GB) kopiert, 99791,3 s, 8,4 MB/s

我無法解釋該警告。它說什麼?警告後我的文件真的是隨機的還是有問題?800950+1 Datensätze einand中的 +0 或 +1 是什麼800950+0 Datensätze aus意思?警告後為+1。是錯誤計數嗎?

答案1

摘要:dd是一個難以正確使用的古怪工具。儘管有大量教程告訴您這一點,但不要使用它。dd有一種「unix 街頭信譽」的氛圍 - 但如果你真正了解你在做什麼,你就會知道你不應該用 10 英尺長的桿子去碰它。

dd每個區塊對系統呼叫進行一次呼叫read(由 的值定義bs)。無法保證read系統呼叫會傳回與指定緩衝區大小一樣多的資料。這通常適用於常規文件和區塊設備,但不適用於管道和某些字元設備。看dd什麼時候適合複製資料? (或者,什麼時候 read() 和 write() 是部分的)了解更多。如果read系統呼叫傳回的資料少於一個完整區塊,則dd傳送部分區塊。它仍然複製指定數量的區塊,因此傳輸的位元組總數小於請求的位元組數。

關於「部分讀取」的警告正是告訴您這一點:其中一次讀取是部分讀取,因此dd傳輸了不完整的區塊。在區塊計數中,+1表示一個區塊被部分讀取;由於輸出計數為+0,因此所有區塊都以讀取形式寫出。

這不會影響資料的隨機性:dd寫出的所有位元組都是從中讀取的位元組/dev/urandom。但您獲得的位元組數比預期少。

Linux/dev/urandom可以滿足任意大的請求(資料來源:extract_entropy_userdrivers/char/random.c),因此dd讀取它時通常是安全的。然而,讀取大量數據需要時間。如果進程收到訊號,read系統呼叫將在填充其輸出緩衝區之前返回。這是正常行為,應用程式應該read循環呼叫;dd由於歷史原因,它並沒有這樣做(dd它的起源是模糊的,但它似乎最初是作為一種訪問磁帶的工具,磁帶有特殊的要求,並且從未被改編為通用工具)。當您檢查進度時,這會向dd進程發送中斷讀取的訊號。您可以選擇知道dd總共要複製多少字節(確保不要中斷它 - 沒有進度檢查,沒有暫停),或者知道dd到目前為止已經複製了多少字節,在這種情況下您無法知道還有多少字節它將複製的位元組。

的版本dd在 GNU coreutils 中(如在非嵌入式 Linux 和 Cygwin 上找到的)有一個標誌fullblock,告訴在循環中dd呼叫(和 for 一樣),因此總是傳輸完整的區塊。錯誤訊息建議您使用它;你應該總是使用它(在輸入和輸出標誌中),除非在非常特殊的情況下(主要是在訪問磁帶時)——如果你使用它,那就是:通常有更好的解決方案(見下文)。readwritedd

dd if=/dev/urandom iflag=fullblock of=file bs=1M count=1000000

確定dd將執行的操作的另一種可能方法是傳遞區塊大小為 1 的區塊read。會發生什麼位元組(這在實踐中不太可能,但有可能發生)。然而,即使有效,速度也非常慢。

一般使用建議dd不使用dd。雖然dd經常被宣傳為存取設備的低階命令,但實際上並非如此:所有的魔力都發生在設備文件(/dev/…)部分,dd只是一個普通工具,很可能被誤用而導致資料遺失。在大多數情況下,有一種更簡單、更安全的方法來完成您想要的操作,至少在 Linux 上是如此。

例如,要在檔案開頭讀取一定數量的字節,只需呼叫head

head -c 1000000m </dev/urandom >file

我在我的機器上做了一個快速基準測試,沒有觀察到dd大塊大小和head.

如果您需要在開始時跳過一些字節,請透過管道tail輸入head

dd if=input of=output count=C bs=B seek=S
<input tail -c +$((S*B+1)) | head -c $((C*B)) >output

如果您想查看進度,請呼叫lsof查看檔案偏移量。這只適用於常規文件(範例中的輸出文件),不適用於字元設備。

lsof -a -p 1234 -d 1
cat /proc/1234/fdinfo/1

您可以致電pv為了獲得進度報告(比 的更好dd),以犧牲管道中的附加項目為代價(在性能方面,幾乎察覺不到)。

答案2

dd當在單次讀取中無法取得足夠的資料來填充區塊時,會出現警告。這種情況發生在不穩定或緩慢的資料來源中,或以比您要求的區塊大小更小的單位寫入資料的來源中。

資料完整性沒有問題,但問題是dd部分讀取仍然算是讀塊。

如果您不使用該count選項,則警告幾乎不重要,這只是效能考慮。但使用 時count,您將無法獲得您要求的資料量。由於部分讀取,of會比count*bs最後小。

因此,當您使用 時,從技術上講您也count應該始終使用。iflag=fullblock

應該+x是部分塊的數量。

答案3

< /dev/urandom \
dd ibs=4k obs=64k |
dd bs=64k count=16000000 >file

^這樣就可以了。這裡的錯誤訊息顯然是錯誤的。dd的緩衝區是明確的因此,緩衝輸入數數您需要明確緩衝的事件。就這些。別買狗屎。

相關內容