AShell(制限付きbash)を使用して乱数を生成するにはどうすればよいですか?またはがないデバイスでBusyBoxバイナリを使用していod
ます$RANDOM
。私のデバイスにはとが/dev/urandom
あり/dev/random
ます。
7 に答える
$RANDOM
とod
はBusyBoxのオプション機能ですが、あなたの質問からすると、それらはバイナリに含まれていないと思います。存在するコメントで/dev/urandom
、それは良いことだと言っています。つまり、必要なのは、乱数ジェネレーターを実装するというはるかに難しい問題ではなく、使用可能な形式でバイトを取得することです。/dev/urandom
ログインキーに対して/dev/ urandomからのランドは安全ですか?を/dev/random
参照してください。。
tr
またはがある場合sed
は、バイトを読み取っ/dev/urandom
て、望ましい文字ではないバイトを破棄できます。また、ストリームから固定バイト数を抽出する方法も必要です。 (有効にhead -c
する必要がある)または(コンパイルする必要がある)のいずれかです。破棄するバイト数が多いほど、このメソッドは遅くなります。それでも、ランダムバイトの生成は通常、外部バイナリをフォークして実行する場合に比べてかなり高速であるため、それらの多くを破棄してもそれほど問題にはなりません。たとえば、次のスニペットは0〜65535の乱数を生成します。FEATURE_FANCY_HEAD
dd
dd
n=65536
while [ $n -ge 65536 ]; do
n=1$(</dev/urandom tr -dc 0-9 | dd bs=5 count=1 2>/dev/null)
n=$((n-100000))
done
バッファリングのために、最終的に保持されるtr
バイトよりもかなり多くのバイトを処理することに注意してくださいdd
。BusyBoxtr
は一度にバッファフル(少なくとも512バイト)を読み取り、入力バッファが完全に処理されるたびに出力バッファをフラッシュするため、上記のコマンドは常に少なくとも512バイトを読み取ります/dev/urandom
(512からの予想されるテイク以降は非常にまれです)入力バイトは10進数の20桁です)。
一意の印刷可能な文字列が必要な場合は、ASCII以外の文字と、おそらくいくつかの迷惑な句読文字を破棄してください。
nonce=$(</dev/urandom tr -dc A-Za-z0-9-_ | head -c 22)
このような状況では、私は小さな専用のCプログラムを書くことを真剣に検討したいと思います。これは、4バイトを読み取り、対応する10進数を出力するものです。read
システムコールとのラッパー以外のlibc関数に依存しないwrite
ため、非常に小さなバイナリを取得できます。コマンドラインで10進整数として渡される可変キャップをサポートすることは、演習として残されています。数百バイトのコードが必要になります(ターゲットがLinuxを実行するのに十分な大きさであるかどうかを心配する必要はありません)。
#include <stddef.h>
#include <unistd.h>
int main () {
int n;
unsigned long x = 0;
unsigned char buf[4];
char dec[11]; /* Must fit 256^sizeof(buf) in decimal plus one byte */
char *start = dec + sizeof(dec) - 1;
n = read(0, buf, sizeof(buf));
if (n < (int)sizeof(buf)) return 1;
for (n = 0; n < (int)sizeof(buf); n++) x = (x << 8 | buf[n]);
*start = '\n';
if (x == 0) *--start = '0';
else while (x != 0) {
--start;
*start = '0' + (x % 10);
x = x / 10;
}
while (n = write(1, start, dec + sizeof(dec) - start),
n > 0 && n < dec + sizeof(dec) - start) {
start += n;
}
return n < 0;
}
</dev/urandom sed 's/[^[:digit:]]\+//g' | head -c10
/ dev/randomまたは/dev/urandomが存在する可能性があります。
もう1つのオプションは、srand()、次にrand()を呼び出す小さなCプログラムを作成することです。
BusyBox 1.22.1でGillesの最初のスニペットを試しましたが、コメントに収まらないパッチがいくつかあります。
while [ $n -gt 65535 ]; do
n=$(</dev/urandom tr -dc 0-9 | dd bs=5 count=1 2>/dev/null | sed -e 's/^0\+//' )
done
- ループ条件は、最大値より大きいかどうかをチェックする必要があります。そうでない場合、実行は0になります。
- 私は沈黙しまし
dd
たstderr
- 先行ゼロが削除されました。これは、8進数として解釈されるコンテキストでサプライズにつながる可能性があります(例
$(( ))
)
Hexdumpとdcはどちらもbusyboxで利用できます。ほとんどランダムの場合は/dev/ urandomを使用し、より良いランダムの場合は/ dev/randomを使用します。これらのオプションはどちらも$RANDOMよりも優れており、どちらもループして印刷可能な文字を探すよりも高速です。
32ビットの10進数の乱数:
CNT=4
RND=$(dc 10 o 0x$(hexdump -e '"%02x" '$CNT' ""' -n $CNT /dev/random) p)
24ビットの16進乱数:
CNT=3
RND=0x$(hexdump -e '"%02x" '$CNT' ""' -n $CNT /dev/random)
数値を小さくするには、hexdumpフォーマット文字列のフォーマットとhexdumpが読み取るバイト数を変更します。
escitalopramのソリューションを試してみると、busybox v1.29.0では機能しませんでしたが、機能を実行するように促されました。
s私は実際に、桁数を要求し、かなりうまく機能するはずのポータブル乱数生成関数を思いついた(これまでのところ、Linux、WinNT10 bash、Busybox、およびmsys2でテスト済み)。
# Get a random number on Windows BusyBox alike, also works on most Unixes
function PoorMansRandomGenerator {
local digits="${1}" # The number of digits of the number to generate
local minimum=1
local maximum
local n=0
if [ "$digits" == "" ]; then
digits=5
fi
# Minimum already has a digit
for n in $(seq 1 $((digits-1))); do
minimum=$minimum"0"
maximum=$maximum"9"
done
maximum=$maximum"9"
#n=0; while [ $n -lt $minimum ]; do n=$n$(dd if=/dev/urandom bs=100 count=1 2>/dev/null | tr -cd '0-9'); done; n=$(echo $n | sed -e 's/^0//')
# bs=19 since if real random strikes, having a 19 digits number is not supported
while [ $n -lt $minimum ] || [ $n -gt $maximum ]; do
if [ $n -lt $minimum ]; then
# Add numbers
n=$n$(dd if=/dev/urandom bs=19 count=1 2>/dev/null | tr -cd '0-9')
n=$(echo $n | sed -e 's/^0//')
if [ "$n" == "" ]; then
n=0
fi
elif [ $n -gt $maximum ]; then
n=$(echo $n | sed 's/.$//')
fi
done
echo $n
}
以下は、1000から9999の間の数値を示しますecho $(PoorMansRandomGenerator 4)
上記の応答をより単純なバージョンに改善しました。これも非常に高速に実行され、Busybox、Linux、msys、およびWinNT10bashと互換性があります。
function PoorMansRandomGenerator {
local digits="${1}" # The number of digits to generate
local number
# Some read bytes can't be used, se we read twice the number of required bytes
dd if=/dev/urandom bs=$digits count=2 2> /dev/null | while read -r -n1 char; do
number=$number$(printf "%d" "'$char")
if [ ${#number} -ge $digits ]; then
echo ${number:0:$digits}
break;
fi
done
}
で使用
echo $(PoorMansRandomGenerator 5)
</ p>