【问题标题】:Why does piping the output of $RANDOM affect the value?为什么管道 $RANDOM 的输出会影响值?
【发布时间】:2018-07-04 23:43:41
【问题描述】:

下面是一个脚本,我希望生成相同的数字对 3 次:

#! /usr/bin/env bash
RANDOM=5
echo " first" $RANDOM
echo "second" $RANDOM

echo

RANDOM=5
echo " first" $RANDOM
echo "second" $RANDOM

echo

RANDOM=5
echo "??????" $RANDOM | cat
echo " first" $RANDOM

相反,管道输出会阻止随机种子被尊重。为什么?

 first 18499
second 9909

 first 18499
second 9909

?????? 843
 first 18499

最终,我希望能够做这样的事情:

#! /usr/bin/env bash
n=3
for i in $( seq $n) ; do
    RANDOM=5
    echo $RANDOM | md5sum | cut -d' ' -f1
done

我可以对后一个脚本进行哪些修改,以使其每次运行时的输出都相同?

【问题讨论】:

    标签: bash random


    【解决方案1】:

    管道中的命令在子shell中执行,子shell有自己独立的环境变量。 $RANDOM 在管道中更新,此更新不会传播到父 shell,这就是为什么您会从以下 echo 中看到 18499

    在这种情况下,您可以改用<<< 重定向来避免管道。重定向不会创建子进程。

    cat <<< "?????? $RANDOM"
    

    (md5sum | cut -d' ' -f1) <<< "$RANDOM"
    

    【讨论】:

    • @zee 那行不通,因为&lt;( ) 确实创建了一个子shell。 @JohnKugelman 我不明白为什么,但你的也不适合我(它就像&lt;&lt;&lt; 字符串在子shell 中被评估,即使它显然不应该)。我已经在 bash v4.4.19、4.2.10 和 v3.2.57 中进行了测试。
    • 我试过many bash versions,这个答案只适用于3.1和3.2.57
    • 如果输出应该是随机的,为什么它是可重复的?种子是什么意思?
    • @LuisMuñoz $RANDOM 的输出基于$RANDOM 的先前值,因此如果让shell 初始化它,将很难预测。如果你在某个时候自己设置它,那么之后它每次都会表现相同(除非你调用一个新的 shell,这会为那个 shell 创建一个新的不可预测的 shell)。它仍然不是一个很好的随机性来源,因为一旦您一次知道它的值,您就可以在随后的时间预测它的值。如果你需要真正的随机性 /dev/urandom 是更好的选择。
    • 重定向不会创建子shell。但是here-docs(和here-strings)可以。或者他们可能,至少。你将如何实施here-docs?您可以将 here-doc 中的文本写入临时文件,并将标准输入重定向到临时文件。或者您可以分叉 bash 进程并将标准输入重定向到孩子正在写入 here-doc 的管道。 Posix 没有指定机制(bash 手册也没有记录它,afaik),但很容易看出使用第二种机制的诱惑。对比i=0; echo $((++i)); echo $ii=0; cat&lt;&lt;&lt;$((++i)); echo $i
    【解决方案2】:

    由于@JohnKugelman 的答案对我不起作用,这里有一个替代方案(它还有一个优点是它可以在不支持&lt;&lt;&lt; 的非bash shell 中工作)。只需将一个临时变量分配给来自$RANDOM 的结果,然后在子shell(或其他奇怪的上下文)中使用该临时变量:

    #! /usr/bin/env bash
    RANDOM=5
    echo " first" $RANDOM
    echo "second" $RANDOM
    
    echo
    
    RANDOM=5
    tmprandom=$RANDOM
    echo " first" $tmprandom | cat
    echo "second" $RANDOM
    

    输出(在 bash v4 下;v3 使用不同的随机数生成器):

     first 18499
    second 9909
    
     first 18499
    second 9909
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-11-06
      • 2015-11-26
      • 1970-01-01
      • 1970-01-01
      • 2016-03-21
      • 2014-05-16
      • 2018-12-23
      相关资源
      最近更新 更多