export MY_VAR="nxf-$(cat /dev/urandom | LC_ALL=C tr -dc 'a-zA-Z0-9' | fold -w 24 | head -n 1)"
这工作正常,但当我将它包含在BASH脚本中并执行它时,脚本执行挂起.
进程树显示以下过程:
4045 ? S 0:00 bash .command.run 4046 ? R 22:38 \_ cat /dev/urandom 4047 ? S 1:03 \_ tr -dc a-zA-Z0-9 4048 ? S 0:34 \_ fold -w 24
似乎urandom永远不会退出.为什么会这样?
解决方法
/ dev / urandom是连续的随机数据流.它永远不会产生文件结束.缓冲读取将填充读取缓冲区,因此即使您将cat的输出传送到其他程序中,在管道关闭之前也不会终止读取.
除了当你读/ dev / urandom时,你正在使用熵(随机性),这是一种宝贵的资源.一旦熵被用完,/ dev / urandom的输出将不那么随机,这就失去了目的. (将收集更多的熵,但建立起来需要一段时间.)
对于/ dev / random来说,所有这些都是双倍的,因为当它耗尽熵时,它通常会阻塞. (除了使/ dev / random成为/ dev / urandom的同义词的操作系统.)
因此,您应该始终准确读取所需的随机数据量,而不是更多.
显然,你的目标是24个字母数字字符.有62个可能的字母数字字符;如果你愿意允许另外两个字符使总数达到64,那么它会大大简化.在这种情况下,你可以通过提取18个字节的随机性并将其传递给base64编码器来产生24个字符.要提取精确数量的数据,请使用专为此目的而设计的dd:
dd bs=18 count=1 if=/dev/urandom | base64 | tr +/ _.
(最后的tr将base64生成的两个非字母数字字符转换为两个不同的字符串,这些字符对文件名更友好.只是一个建议.)
如果您决定使用精确的字母数字字符,则可以使用类似于您当前使用的拒绝策略,但基于上述情况.不幸的是,在这种情况下,不可能准确地预测你需要多少输入,所以最简单的方法是多读一点,并在极少数情况下重试你没有得到足够的:
# Here we produce 28 characters each time until s=$(dd bs=21 count=1 if=/dev/urandom | LC_ALL=C tr -cd A-Za-z0-9) ((${#s} >= 24)); do :; done # When the loop ends we have at least 24 characters; truncate s=${s:0:24}
如果你没有bash,你可以用[${#s} -ge 24]和s = ${s:0:24}替换((${#s}> = 24))s = $(printf%.24s $s)
但是,如果您只是尝试生成好的随机文件名,则应使用mktemp,它允许您为名称指定骨架,并验证生成的名称是否已存在.见man mktemp.