Ubuntuシステムで次のコマンドを実行しています。
dd if=/dev/random of=Rand bs=1K count=2
しかし、実行するたびに、サイズの異なるファイルができてしまいます。どうしてこれなの?ランダムなデータで満たされた特定のサイズのファイルを生成するにはどうすればよいですか?
dd
の特異な動作とLinuxの_/dev/random
_の特異な動作の組み合わせを観察しています。ちなみに、どちらも仕事に適したツールであることはめったにありません。
Linuxの_/dev/random
_は、データを控えめに返します。これは、疑似乱数ジェネレータのエントロピーが非常に速い速度で消滅するという仮定に基づいています。新しいエントロピーの収集は遅いため、_/dev/random
_は通常、一度に数バイトのみを放棄します。
dd
は、最初はテープデバイスで動作することを目的とした古い、気難しいプログラムです。 1kBの1ブロックを読み取るように指示すると、1ブロックを読み取ろうとします。読み取りが1024バイト未満を返す場合は、それだけで十分です。したがって、_dd if=/dev/random bs=1K count=2
_は2つのread(2)
呼び出しを行います。 _/dev/random
_から読み取っているので、2つのread
呼び出しは通常、利用可能なエントロピーに応じて異なる数の数バイトのみを返します。参照 ddがデータのコピーに適しているのはいつですか?(または、read()とwrite()が部分的である場合)
OSインストーラーまたはクローンを設計しているのでない限り、Linuxでは_/dev/random
_を使用しないでください。常に_/dev/urandom
_を使用してください。 urandom
manページは誤解を招く可能性があります。 _/dev/urandom
_は、実際には暗号化に適しています。長期間有効なキーを生成する場合にも適しています。 _/dev/urandom
_の唯一の制限は、十分なエントロピーを指定する必要があることです。 Linuxディストリビューションは通常、再起動間のエントロピーを保存するため、十分なエントロピーがない可能性があるのは、フレッシュインストール時のみです。エントロピーは実際には衰えません。詳細については、 / dev/urandomのRandはログインキーに対して安全ですか? および / dev/randomエントロピープールをフィードしますか? を参照してください。
dd
のほとんどの使用法は、head
やtail
などのツールでよりよく表現されます。 2kBのランダムバイトが必要な場合は、次を実行します。
_head -c 2k </dev/urandom >Rand
_
古いLinuxカーネルでは、
_dd if=/dev/urandom of=Rand bs=1k count=2
_
なぜなら、_/dev/urandom
_は、要求されたバイト数を喜んで返したからです。しかし、カーネル3.16以降、これは当てはまりません 現在は32MBに制限されています 。
一般に、dd
を使用して固定バイト数を抽出する必要があり、その入力が通常のファイルまたはブロックデバイスからのものでない場合は、バイトごとに読み取る必要があります:_dd bs=1 count=2048
_。
RHEL 5ボックスのman 4 random
から:
/ dev/randomデバイスは、読み取られると、エントロピープール内のノイズの推定ビット数内のランダムバイトのみを返します。
そのマシンで213バイトのファイルを取得します。ランダムに男4に戻る:
読み取られると、/ dev/urandomデバイスは要求されたバイト数を返します。
dd if=/dev/urandom of=Rand bs=1K count=2
の呼び出しごとに2048バイトを取得します
違いは、dd if=/dev/random ...
の呼び出しの間にマシンが生成するエントロピーの量が原因であると私は結論付けます
dd
がデータをドロップするのはなぜですか? ...Gillesがdd
に関するこの魅力的な質問を投げかけました:
ddがデータのコピーに適しているのはいつですか(または、read()とwrite()が部分的である場合)
これはその質問からの抜粋です:
* ... ddに誤りをつけることは難しくありません。たとえば、このコードを試してください:**yes | dd of=out bs=1024k count=10
、出力ファイルのサイズを確認します(10MBをはるかに下回る可能性があります)。
(質問の最後にある)私のコメントは別として、このようなものは見るのが繰り返しです...ファイル$trnd
でバイトをキャッチします。私は任意にbs = 8を選択しました
マウスを動かして、速度が上がるのを見てください。
コンピュータがアイドル状態(AFKでネットワークアクティビティがない)で、エントロピープールを使い果たした後、2時間かかりました1192バイトのみを収集するのに12分、その時点でキャンセルしました。
次に、マウスを連続的に動かして、比較的短い1分15秒同じバイト数を収集します。
これは、エントロピーの収集がCPU速度ベースではなく、ランダムイベントベースであり、私のUbuntuシステムがマウスの1つを使用していることをかなり明確に示していますその重要なランダム因子。
get=2048
trnd=/tmp/$USER.rnd; >"$trnd"
while (( $(wc -c <"$trnd") < $get )) ;do
dd if=/dev/random bs=8 count=1 2>/dev/null >>"$trnd"
echo -n "itt: $((i+=1)) ct: "; wc -c <"$trnd"
done
truncate -s $get "$trnd"
echo -e "\nfinal count: "; wc -c <"$trnd"
dd
is isdesignedfor block-これは通常、必要に応じて可変サイズの入力から読み取るのに最適なツールですimmediatelydd
は現在の読み取りを将来のwrite()
にバッファリングしないため(ただし、 ibs)よりも大きいobsを使用して、そのように明示的に構成しますが、代わりにwrite()
が読み取るすべてのものがread()
になるとすぐに(およびオプションでそれを処理します)。
ここにいくつかの重要な definitions があります:
ibs=
expr
expr
でバイト単位で指定します(デフォルトは512)。obs=
expr
expr
で出力ブロックサイズをバイト単位で指定します(デフォルトは512)。bs=
expr
expr
バイトに設定し、ibs=
とobs=
を置き換えます。 sync
、noerror
、およびnotrunc
以外の変換が指定されていない場合、各入力ブロックは、短いブロックを集約せずに単一のブロックとして出力にコピーされます。つまり、ibs
とobs
を一緒にbs
として定義すると、ibs
が優先されますが、それ以外の場合、具体的にはobs
またはcbs
はそうします。
以下は、ibs
が最も重要な例です。 /dev/random
プールがいっぱいになるまでの時間を追跡したい場合は、このようなことをするかもしれません...
dd "ibs=$size" conv=sync "count=$lmt" \
if=/dev/random of="$somefile"
dd
であるため、if=
のターゲットが読み取り可能である限り、常にalwaysは同じサイズの出力ファイルになります。 sync
hronizeはnullで読み込まれたブロックをブロックします。つまり、read()
$((size=10))
回の入力ブロックに対してdd
$((count=5))
sを実行し、read()
ファイルが2バイトを返す場合、次に、8バイト、12バイト、2バイト、4バイトのように、dd
は次のような出力ファイルに書き込みます
2 read bytes 8NULs \
8 read bytes 2NULs \
10 read bytes 0NULs \
4 read bytes 6NULs \
4 read bytes 6NULs
...dd
は、デフォルトでは遅延しないためです。したがって、インストリームを追跡して他のプロセスの書き込みを区切る必要がある場合は、dd
が最適です。
通常のファイルに一定量のデータを書き込むだけの場合は、ここで行った他のステートメントとは逆に、これにdd
を使用することもできます-かなり簡単ですが、1つ以上必要です。信頼できるブロッキングfactor。
たとえば、次の場合:
{ dd ibs="$size" obs="${size}x$block_factor" |
dd bs="${size}x$blockfactor" "count=$lmt"
} <infile >outfile
...最初のdd
は、パイプ間のすべてのwrite()
に対して少なくとも1つのibs="$size"
出力ブロックを満たすために必要な数のobs="${size}x$block_factor"
入力ブロックをバッファリングしますそして2番目のdd
。これは、2番目のdd
がcount="$lmt"
を使用して出力を確実に制限できることを意味します。これは、最初に作成するすべてのwrite()
がそのI/Oブロックサイズと一致するためです-無条件最初のdd
がread()
を何回実行する必要があるか。
そしてthatはdd
を使用してパイプやその他のタイプの特殊ファイルを確実に読み取る方法です-ほんの少しの計算で。