web-dev-qa-db-ja.com

指定された行数で/ dev / urandomからのストリームでファイルを埋める方法は?

ユーザー定義の行数と1行あたりの文字数を使用して、ランダムな0と1のシーケンスでファイルを埋めようとしています。

最初のステップは、0と1のランダムストリームを取得することです。

cat /dev/urandom | tr -dc 01

次に、このストリームでファイルを埋めようとしました(そして、ctrl + cで埋めるプロセスを終了します)

cat /dev/urandom | tr -dc 01 > foo

そのように作成されたfooファイルの行数を数えると、0行になります。

cat foo | wc -l
0

ここでストリームを制御しようとしたので、名前付きパイプを作成し、ストリームをそのパイプに向けました。次に、ddコマンドを使用して名前付きパイプに接続しましたが、この方法で1行あたりの文字数とファイル内の行数を制御することはできませんでした。

makefifo namedpipe
cat /dev/urandom | tr -dc 01 > namedpipe
dd if=namedpipe of=foo bs=10 count=5

fooファイルは確かに0と1の50バイトでいっぱいになりましたが、行数はまだ0でした。

どうすれば解決できますか。ファイルに各文字数の改行を挿入する必要があると思いますが、そうであれば、方法がわかりません。

4
Abdul Al Hazred

foldはどうですか?それはcoreutilsの一部です...

$ tr -dc 01 < /dev/urandom | fold -w 30 | head -n 5
001010000111110001100101101101
000101110011011100100101111000
111010101011100101010110111001
111011000000000101111110110100
110011010111001110011010100011

または、それが利用できない場合は、awkのフレーバー:

$ tr -dc 01 < /dev/urandom | awk \$0=RT RS=.\{,30} | head -n 5
000100010010001110100110100111
101010010100100110111010001110
100011100101001010111101001111
010010100111100101101100010100
001101100000101001111011011000

または、ループで何かを行うこともできます...

$ for line in $(seq 1 5)
> do
>     echo $(tr -dc 01 < /dev/urandom | head -c 30)
> done
100101100111011110010010100000
000000010000010010110111101011
010000111110010010000000010100
001110110001111011101011001001
001010111011000111110001100110

他の方法があると確信しています...カスタム形式のhexdumpでそれができると思いましたが、明らかにそうではありません...;)

8
frostschutz
LC_ALL=C </dev/urandom \
tr '\0-\377' '[0*128][1*]' |
dd ibs=50 cbs=10 conv=unblock count=1

これにより、すべての入力ASCIIバイトが変換されますLC_ALL=Cが指定されているためすべてのバイトになります)偶数分布で0または1のいずれかに変換されます。 \0\177の間の最初の128バイトはゼロに変換され、\200-\377は1に変換されます。したがって、すべての入力バイトを使用しても、1または0のみのランダムに順序付けられたシーケンスを出力できます。 。

ddを使用するのは正しいことですが、11バイトの5つの出力行を取得するためにbs=ブロックサイズを設定する必要はありません(10 + \newline )ピース。代わりに、count=1バイトの入力ブロックにibs=50シングルread()を指定する必要があります。これは、5つのcbs=10サイズの変換ブロックとconv=unblockedに分割できます。 cbs-sizeで、末尾のスペースをすべて削除した後、各変換ブロックに\newlineを追加します(その中にはありません)

だから私はそれを実行して印刷しました:

1101001010
1100001001
1101110100
1011011000
1011110100
1+0 records in
0+1 records out
55 bytes (55 B) copied, 0.00176591 s, 31.1 kB/s

また、あるメソッドと別のメソッドの速度の比較を示し、パイプからのddの読み取りが、を説明するブロックファクターで読み込んだ場合に問題にならないことを示すために、アンティを少し上げました。ユーティリティのバッファサイズを書き込みます。だから私は最初にした:

time (
LC_ALL=C </dev/urandom \
tr -dc 01 |
dd ibs=4k cbs=10 conv=unblock count=k|
grep \[^01])

... stdoutで出力をレンダリングしませんでした(したがって、grepは0または1以外の何にも一致しませんでした)そしてstderrで次のようになります:

1024+0 records in
9011+1 records out
4613735 bytes (4.6 MB) copied, 25.8898 s, 178 kB/s
( LC_ALL=C tr -dc 01 < /dev/urandom |\
  dd ibs=4k cbs=10 conv=unblock count=k |...)\
0.80s user 25.42s system 101% cpu 25.921 total

上記の情報は、パイプラインがシステムコールの待機に25.5秒を費やしたことを示しています。 OK。しかし、それはまた、ddが4096バイトサイズの入力レコードの1024個すべてを読み込み完全にであり、初期のread()のために1つも切り捨てられなかったことを示しています。 return-これは、trが4kブロックでパイプ出力をバッファリングするためです。

とにかく、それを逆に行うこと、またはスペクトラム拡散ですべてのランダム入力を変換することは、次のことでした。

time (
LC_ALL=C </dev/urandom \
tr '\0-\377' '[0*128][1*]' |
dd ibs=4k cbs=10 conv=unblock count=k|
grep '[^01]')

繰り返しになりますが、stdoutには何もありませんでした-したがって、ddの出力のallは、ゼロまたは1または改行のいずれかでした-そしてこれはstderrにあります:

1024+0 records in
9011+1 records out
4613735 bytes (4.6 MB) copied, 0.554202 s, 8.3 MB/s
( LC_ALL=C tr '\0-\377' '[0*128][1*]' \
  < /dev/urandom|dd ibs=4k cbs=10 ...)\
0.61s user 0.36s system 171% cpu 0.571 total

...これもまた、ddが1024個の完全な入力レコードすべて+0個の切り捨てられた入力レコードを読み込んだことを示していますが、処理時間は大幅に異なります。 trddは実際にはここで並行して動作し、プロセス全体が.6秒未満で完了するよりも、別々のコアで合計より多くのユーザー時間を使用します。それは少し速いです。

4
mikeserv

生成プロセス中に改行を追加するには、次のようにします。

{ process-without-terminating-newline ; echo ;} > outfile

既存のファイルに追加するには、次のようにします。

echo >> outfile
1
Janis

次に、このストリームでファイルを埋めようとしました(そして、ctrl + cで埋めるプロセスを終了します)

cat /dev/urandom | tr -dc 01 > foo

そのように作成されたfooファイルの行数を数えると、0行になります。

cat foo | wc -l
0

cattrbuffer の両方の出力。を押すと Ctrl+C、いずれかのコマンドのバッファに残っているデータはすべて失われます。 trがまだ完全なバッファの価値を蓄積していないのに十分早くプログラムを中断したので、何も書き出されていませんでした。

文字デバイスまたはパイプからの読み取りにddを使用しないでください

Linuxでは、headを使用して、特定のバイト数の後にデータを切り捨てることができます。

i=0
while [ "$i" -lt "$number_of_lines" ]; do
  </dev/urandom tr -dc 01 | head -c "$bits_per_line"; echo
  i=$((i+1))
done >foo

または、必要なバイト数を生成し、foldを使用して改行を挿入します。

</dev/urandom tr -dc 01 |
fold -w "$bits_per_line" |
head -n "$number_of_lines"

0または1以外のすべてのバイトを拒否するのはかなり遅いです:入力の127/128番目を拒否しています。基数2で出力を生成する標準ユーティリティはありませんが、odを使用して16進数を生成し、桁ごとに変換できます。

</dev/urandom od -An -tx1 |
sed 's/ //g; s/0/@@@@/g; s/1/@@@`/g; s/2/@@`@/g; s/3/@@``/g; s/4/@`@@/g; s/5/@`@`/g; s/6/@``@/g; s/7/@```/g; s/8/`@@@/g; s/9/`@@`/g; s/[Aa]/`@`@/g; s/[Bb]/`@``/g; s/[Cc]/``@@/g; s/[Dd]/``@`/g; s/[Ee]/```@/g; s/[Ff]/````/g; y/@`/01/' |
fold -w "$bits_per_line" |
head -n "$number_of_lines"

xxdがある場合は、それを使用してバイトを基数2の表現に変換できます。 1行あたりのビット数が8の倍数の場合は、-cオプションを使用して必要に応じて改行を挿入し、-lを使用して行数の後に停止することもできます。

</dev/urandom xxd -b -c "$bytes_per_line" -l "$((bytes_per_line * number_of_lines))" |
sed -e 's/  .*//' -e 's/.*://'