如何仅使用符合POSIX的shell工具生成字母数字字符串?

时间:2018-05-20 02:39:03

标签: string shell posix

我正在尝试使用符合POSIX标准的shell工具生成一个八字符的字母数字字符串。我正在尝试使用/ dev / urandom来生成这个字符串(顺便说一句,我不知道/ dev / random和/ dev / urandom都没有被POSIX指定,但是我会继续使用它,因为它们出现在Linux上, FreeBSD,Mac OS,AIX等。)

有很多指南显示了如何做到这一点,但我发现没有任何指南接近于正确。特别是我一直看到使用head -c(-c参数未在POSIX中定义),如下所示:

head /dev/urandom | tr -dc A-Za-z0-9 | head -c 13 ; echo ''

我所担心的另一个问题是,我所看到的几乎所有解决方案都没有尊重字节流和字符流之间的区别,这让我担心我会生成不安全的字符串。

这是我能想到的最好的,但我并不完全理解它:

strings -n 1 < /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 8 | head -n 1

它符合POSIX(减去/ dev / urandom)但我是否正确地完成了我的结束?如果是这样,是否有更好的方法来实现这一目标?如果有一种方法可以生成一个没有/ dev / urandom的随机字符串,那也很酷,但我想我正在梦想那个。

3 个答案:

答案 0 :(得分:2)

只需使用awk,POSIX要求提供rand功能。

$ cat password.awk
BEGIN {
    srand();
    chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
    s = "";
    for(i=0;i<8;i++) {
        s = s "" substr(chars, int(rand()*62), 1);
    }
    print s
}
$ awk -f password.awk
Cl7A4KVx

(这几乎可以肯定是代码更高的东西;我的awk技能有些限制。)

如果您需要多个密码,请将所需的数字作为参数传递,这样您就不需要每秒运行awk次:

BEGIN {
  srand();
  chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
  for(i=0;i<n;i++) {
    s = "";
    for(j=0;j<8;j++) {
      s = s "" substr(chars, int(rand()*62), 1);
    }
    print s
  }
}

要传递值n,请以awk -v n=5 -f password.awk运行以生成5个密码。

或者,您可以将其他种子直接传递给awk

BEGIN {
  srand(seed);
  chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
  s = "";
  for(i=0;i<8;i++) {
      s = s "" substr(chars, int(rand()*62), 1);
  }
  print s
}

awk -v seed=$newseed -f password.akw。请注意,newseed本身每次都需要具有不同的值,但使用简单的连续序列的种子就足够了。

seed=$(date +%s)
awk -v seed=$seed -f password.awk; seed=$((seed + 1))
awk -v seed=$seed -f password.awk; seed=$((seed + 1))
awk -v seed=$seed -f password.awk; seed=$((seed + 1))
# etc

答案 1 :(得分:0)

试试这个:

head -n 1 /dev/urandom | hexdump | head -n 1 | sed ‘s/0+| //g’ | sed ‘s/\(......\).*/\1/g’

答案 2 :(得分:0)

只有POSIX工具箱的八个“随机”字母数字字符?很好,一个挑战!

让我们首先观察Base-64编码几乎只使用字母数字(以及+/),而精彩的POSIX人员已经使用-m添加了Base-64支持uuencode实用程序。

接下来,我们从哪里得到一些(伪?几乎?)随机性?再次观察当前的进程列表是非常随意的,特别是如果它包含长格式的所有进程,CPU时间等等。

我们使用POSIXly cksum实用程序进一步压缩ps熵,因为ps输出的第一行是非常常量的,我们必须在uuencoded输出中查找合适的行(这很麻烦)。

到目前为止我们已经

$ ps|cksum|uuencode -m -
begin-base64 644 -
MjUwMDcyMjY3NSAxOTExCg==
====

运行这几次我们注意到(或知道)第二行中的前两个字符不是很随机,因为它们包含行的长度。所以我们用

从第2行的第3位提取8个字符
$ ps|cksum|uuencode -m -|sed -n 's,[+/],0,g; 2s/^..\(........\).*/\1/p'
kzNDkzMj
$ ps|cksum|uuencode -m -|sed -n 's,[+/],0,g; 2s/^..\(........\).*/\1/p'
I0NTcxND

并将不需要的+/转置为0。每次调用几乎都可以保证不同的结果,因为三重管道中的命令的进程ID随每次运行而不同。

瞧!不需要/dev/urandom: - )