使用种子洗牌 bash 中的数字
Shuffling numbers in bash using seed
我想创建一个整数数组,其中的数字从 1...N 开始。每个数字在此数组中出现一次。例如 array = {1, 3, 5, 2, 4} 当 N = 5.
为了生成这个数组,我使用了 shuffle 方法:
array=($(shuf -i 1-$N -n $N ))
它工作正常。但是,我想在此代码中添加种子,以确保每次 运行 使用相同种子的代码时,我都会得到相同的数组。是否可以使用 shuffle 方法来做到这一点?
shuf
的 GNU 实现有一个 --random-source
参数。将此参数与已知内容的文件名一起传递将产生一组可靠的输出。
请参阅 GNU coreutils 手册中的 Random sources 文档,其中包含以下示例实现:
get_seeded_random()
{
seed=""
openssl enc -aes-256-ctr -pass pass:"$seed" -nosalt \
</dev/zero 2>/dev/null
}
shuf -i1-100 --random-source=<(get_seeded_random 42)
要以不依赖 string-splitting(以及 IFS 的当前值)的方式将结果加载到 bash 数组中,您的实现可能如下所示:
# with bash 4.0 or newer
readarray -t array < <(shuf -i1-100 --random-source=<(get_seeded_random 42))
# or, supporting bash 3.x as well
IFS=$'\n' read -r -d '' -a array \
< <(shuf -i1-100 --random-source=<(get_seeded_random 42) && printf '[=11=]')
单独使用 bash(不使用 shuf
或 openssl
等外部工具,您可以使用 $RANDOM
,您可以使用 pseudo-random 输入播种,例如所以:
RANDOM=$$
或
RANDOM=$(date '+%s')
等等
您可以使用 {1..N}
.
等表达式 select 一系列数字
declare -a a=()
for n in {1..5}; do
a[$RANDOM]=$n
done
echo "${a[@]}"
上面编码的这个解决方案在重复随机值的情况下有 non-zero 失败的风险,这可以通过一些额外的代码来减轻,或者通过扩展随机范围来减少,例如使用 bit-shifting 生成 30 位无符号整数而不是 15 位无符号整数:
...
a[$(( (RANDOM<<15)+RANDOM ))]=$n
...
此解决方案的输出是 "randomized",因为在 bash 中,non-associative 数组的元素自然按其索引值进行数字排序。
请注意,"sequential" 也是一个有效的随机顺序。 :-)
$ a=(); for n in {1..5}; do a[$RANDOM]=$n; done; declare -p a
declare -a a=([7460]="5" [12697]="3" [16841]="2" [21485]="1" [32493]="4")
$ a=(); for n in {1..5}; do a[$RANDOM]=$n; done; declare -p a
declare -a a=([1444]="1" [12162]="2" [17774]="3" [29827]="4" [31840]="5")
我想创建一个整数数组,其中的数字从 1...N 开始。每个数字在此数组中出现一次。例如 array = {1, 3, 5, 2, 4} 当 N = 5.
为了生成这个数组,我使用了 shuffle 方法:
array=($(shuf -i 1-$N -n $N ))
它工作正常。但是,我想在此代码中添加种子,以确保每次 运行 使用相同种子的代码时,我都会得到相同的数组。是否可以使用 shuffle 方法来做到这一点?
shuf
的 GNU 实现有一个 --random-source
参数。将此参数与已知内容的文件名一起传递将产生一组可靠的输出。
请参阅 GNU coreutils 手册中的 Random sources 文档,其中包含以下示例实现:
get_seeded_random() { seed="" openssl enc -aes-256-ctr -pass pass:"$seed" -nosalt \ </dev/zero 2>/dev/null } shuf -i1-100 --random-source=<(get_seeded_random 42)
要以不依赖 string-splitting(以及 IFS 的当前值)的方式将结果加载到 bash 数组中,您的实现可能如下所示:
# with bash 4.0 or newer
readarray -t array < <(shuf -i1-100 --random-source=<(get_seeded_random 42))
# or, supporting bash 3.x as well
IFS=$'\n' read -r -d '' -a array \
< <(shuf -i1-100 --random-source=<(get_seeded_random 42) && printf '[=11=]')
单独使用 bash(不使用 shuf
或 openssl
等外部工具,您可以使用 $RANDOM
,您可以使用 pseudo-random 输入播种,例如所以:
RANDOM=$$
或
RANDOM=$(date '+%s')
等等
您可以使用 {1..N}
.
declare -a a=()
for n in {1..5}; do
a[$RANDOM]=$n
done
echo "${a[@]}"
上面编码的这个解决方案在重复随机值的情况下有 non-zero 失败的风险,这可以通过一些额外的代码来减轻,或者通过扩展随机范围来减少,例如使用 bit-shifting 生成 30 位无符号整数而不是 15 位无符号整数:
...
a[$(( (RANDOM<<15)+RANDOM ))]=$n
...
此解决方案的输出是 "randomized",因为在 bash 中,non-associative 数组的元素自然按其索引值进行数字排序。
请注意,"sequential" 也是一个有效的随机顺序。 :-)
$ a=(); for n in {1..5}; do a[$RANDOM]=$n; done; declare -p a
declare -a a=([7460]="5" [12697]="3" [16841]="2" [21485]="1" [32493]="4")
$ a=(); for n in {1..5}; do a[$RANDOM]=$n; done; declare -p a
declare -a a=([1444]="1" [12162]="2" [17774]="3" [29827]="4" [31840]="5")