zsh 随机生成器中的奇怪行为

use*_*781 1 zsh random command-substitution subshell

我有这个脚本从定义的字符列表中生成 $1 位的混合随机字符作为数组。

#!/bin/bash

charlist1=(a b c d e f g h i j k l m n o p q r s t u v w x y z)
charlist2=(0 1 2 3 4 5 6 7 8 9)
charlists=(${charlist1[*]} ${charlist2[*]})

i="1"
while [ $i -le $1 ]; do
    out=$out`echo -n ${charlists[$(($RANDOM % ${#charlists[*]}))]}`
    i=$(( i + 1 ))
done

echo $out
Run Code Online (Sandbox Code Playgroud)

它在 bash 中运行良好,但是如果我用 zsh 调用它,zsh that_script_above.sh 6它只会生成 6 位相同字符的数字,如下所示:

>>> zsh that_script_above.sh 6
llllll
>>> zsh that_script_above.sh 6
bbbbbb
Run Code Online (Sandbox Code Playgroud)

如果我将该脚本修改为如下所示:

#!/bin/bash

charlist1=(a b c d e f g h i j k l m n o p q r s t u v w x y z)
charlist2=(0 1 2 3 4 5 6 7 8 9)
charlists=(${charlist1[*]} ${charlist2[*]})

i="1"
while [ $i -le $1 ]; do

    echo -n ${charlists[$(($RANDOM % ${#charlists[*]}))]}

    i=$(( i + 1 ))
done

echo
Run Code Online (Sandbox Code Playgroud)

它可以很好地满足我对bash和 的期望zsh

所以,这是我的问题:

  1. 有人可以向我解释我上面提到的 zsh bash 行为的问题吗?
  2. 以及如何在具有可自定义变量的 bash 中使用 for 循环?因为它似乎for i in {1..$1}在 bash 中不起作用。

dav*_*085 9

一季度。命令替换(反引号)使用子外壳,并且在 zsh 中子外壳的 RNG 状态未重新设定种子。由于您重复创建一个新的子外壳而不$RANDOM在父外壳中使用,因此在每个子外壳中都会获得相同的值。请参阅:
https : //stackoverflow.com/questions/32577117/references-to-random-in-subshel​​ls-all-returning-identical-values
https://superuser.com/questions/1210435/different-behavior-of-in -zsh-and-bash-functions

您不需要 command-substitution 和 echo,也不需要 the$((..))因为数组下标已经被评估为算术表达式,但是您确实需要 +1 因为 zsh 数组是 1-origin(你很幸运没有碰巧打到 0):

 out=$out${charlists[ $RANDOM % ${#charlists[*]} + 1 ]}
Run Code Online (Sandbox Code Playgroud)

旁白:即使您确实需要echo在命令中替换,您也不需要,-n因为命令替换本身会从捕获和替换的数据中删除任何尾随换行符。

Q2。bash 在进行参数扩展(以及命令和算术替换/扩展)之前先进行大括号扩展,但 zsh(和 ksh)在它之后进行。你可以使用for i in $(seq 1 $1)or yucky 但内置for i in $(eval "echo {1..$n}")