如何从Bash的字符串/数组中选择一个随机字符?

时间:2018-02-17 02:49:08

标签: bash random

我有一个例子,我试图在一组字母中随机生成一个字母(即var =“abcdefghijklmnopqrstuvwxyz”)。

我将如何:

var="abcdefghijklmnopqrstuvwxyz"

echo "${var}"

收益: some_letter

关键是,我正在尝试从我选择的选择中自动生成随机字母 。无论是数组还是字符串都没关系。

3 个答案:

答案 0 :(得分:9)

var="abcdefghijklmnopqrstuvwxyz"
echo "${var:$(( RANDOM % ${#var} )):1}" # pick a 1 char substring starting at a random position

这是因为:

  • ${var:START:LEN}parameter expansion,可扩展为$var
  • 的替代品
  • ${#var}是一个参数扩展,扩展为字符串变量var
  • 的内容长度
  • $(( ))创建一个算术上下文,其中假定非数字字符串引用变量名称(因此可以使用RANDOM代替$RANDOM)。
  • $RANDOM,每次评估时,都会扩展为0到32767之间的随机整数。
  • $RANDOM % ${#var}将该随机整数的余数除以名为var的字符串中的字符数;因此,它将在0和(var - 1的长度)之间,并且几乎随机分割(如果 - var的长度不是&#39 ; t均匀分为32768,然后某些字符被选中的几率略高于其他字符。)

因此,${var:$(( RANDOM % ${#var} )) : 1}每次评估时,都会在字符串中选择一个位置,并扩展到其中的单字符范围。

答案 1 :(得分:1)

对于大多数实际案例,Charles Duffy的解决方案是前进的方向。但是,如果您的随机字符选择必须是统一的,那么当您想要使用RANDOM时,故事会变得稍微复杂一些(请参阅下面的说明)。最好的方法是使用shufshuf生成给定范围的随机排列,并允许您选择第一个数字,如shuf -i 0-25 -n1,以便您可以使用

var="abcdefghijklmnopqrstuvwxyz"
echo ${var:$(shuf -i 0-$((${#var}-1)) -n1):1}

随机变量RANDOM生成0到32767之间的伪随机数。这意味着如果要生成0n之间的随机数,则无法使用国防部。这里的问题是第一个32768%n数字将有更高的机会被绘制。使用以下脚本可以很容易地看到这一点:

% for i in {0..32767}; do echo $((i%5)); done | sort -g | uniq -c
   6554 0
   6554 1
   6554 2
   6553 3  < smaller change to hit 3
   6553 4  < smaller chance to hit 4

另一种经典方法是将随机数生成器的范围映射到请求范围n*RANDOM/32768。但是,这仅适用于生成实数的随机数生成器。 RANDOM生成一个整数,因此您只需改变问题:

% for i in {0..32767}; do echo $((5*i/32768)); done | sort -g | uniq -c
   6554 0
   6554 1
   6553 2  < smaller chance to hit 2
   6554 3
   6553 4  < smaller chance to hit 4

如果您想使用RANDOM,最好的方法是跳过不需要的值,这可以通过简单的while循环来实现

var="abcdefghijklmnopqrstuvwxyz"
n=${#var}
idx=32769; while (( idx >= (32768/n)*n )); do idx=$RANDOM; done
char=${var:$idx:1}

注意:你可能会在while循环中陷入永恒状态。

评论:我们不评论RANDOM背后的随机数生成器有多好。我们所做的只是引用来源中的评论:

  

来源bash 4.4.18(variables.c

/* A linear congruential random number generator based on the example
   one in the ANSI C standard. This one isn't very good, but a more
   complicated one is overkill.
*/

答案 2 :(得分:1)

您也可以使用一种更简洁的方式使用shuf

基本上,您将字符串分成两行,然后按常规方式使用shuf

使用fold进行拆分

echo "abcdefghijklmnopqrstuvwxyz" | fold -w1 | shuf -n1

使用grep进行拆分

echo "abcdefghijklmnopqrstuvwxyz" | grep -o . | shuf -n1