如何仅使用 POSIX 兼容的 shell 工具生成字母数字字符串?
How can I generate an alphanumeric string using only POSIX-compliant shell tools?
我正在尝试使用 POSIX 兼容的 shell 工具生成八个字符的字母数字字符串。我正在尝试使用 /dev/urandom 来生成此字符串(顺便说一下,我不知道 /dev/random 和 /dev/urandom 未由 POSIX 指定,但我要去因为它们存在于 Linux、FreeBSD、Mac OS、AIX 等)
有大量指南说明了如何做到这一点,但我发现 none 几乎是正确的。特别是我一直看到 head -c 的使用(-c 参数未在 POSIX 中定义),如下所示:
head /dev/urandom | tr -dc A-Za-z0-9 | head -c 13 ; echo ''
我担心的另一个问题是,几乎 none 我见过的解决方案都尊重字节流和字符流之间的区别,这让我担心我生成的字符串不安全。
这是我能想到的最好的,但我并不完全理解它:
strings -n 1 < /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 8 | head -n 1
它符合 POSIX 标准(减去 /dev/urandom)但我是否正确地达到了目标?如果是这样,是否有更好的方法来实现这一目标?如果有一种方法可以在没有 /dev/urandom 的情况下生成随机字符串,那也会很酷,但我想我在做梦。
试试这个:
head -n 1 /dev/urandom | hexdump | head -n 1 | sed ‘s/0+| //g’ | sed ‘s/\(......\).*//g’
只需使用 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
八个 "random" 字母数字字符,只有 POSIX 工具箱?很好,一个挑战!
让我们从观察 Base-64 encoding uses almost only alphanumerics (and +
and /
) and the wonderful POSIX people have added Base-64 support with -m
to the uuencode 效用开始。
接下来,我们从哪里得到一些(pseudo?几乎?)随机性?再次观察当前进程列表是相当随意的,特别是如果它包含长格式的所有进程,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/^..\(........\).*//p'
kzNDkzMj
$ ps|cksum|uuencode -m -|sed -n 's,[+/],0,g; 2s/^..\(........\).*//p'
I0NTcxND
并将不需要的 +
和 /
转置为 0
。几乎可以保证每次调用都会得到不同的结果,因为三重管道中命令的进程 ID 与每个 运行 不同。
瞧!不需要 /dev/urandom
:-)
我正在尝试使用 POSIX 兼容的 shell 工具生成八个字符的字母数字字符串。我正在尝试使用 /dev/urandom 来生成此字符串(顺便说一下,我不知道 /dev/random 和 /dev/urandom 未由 POSIX 指定,但我要去因为它们存在于 Linux、FreeBSD、Mac OS、AIX 等)
有大量指南说明了如何做到这一点,但我发现 none 几乎是正确的。特别是我一直看到 head -c 的使用(-c 参数未在 POSIX 中定义),如下所示:
head /dev/urandom | tr -dc A-Za-z0-9 | head -c 13 ; echo ''
我担心的另一个问题是,几乎 none 我见过的解决方案都尊重字节流和字符流之间的区别,这让我担心我生成的字符串不安全。
这是我能想到的最好的,但我并不完全理解它:
strings -n 1 < /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 8 | head -n 1
它符合 POSIX 标准(减去 /dev/urandom)但我是否正确地达到了目标?如果是这样,是否有更好的方法来实现这一目标?如果有一种方法可以在没有 /dev/urandom 的情况下生成随机字符串,那也会很酷,但我想我在做梦。
试试这个:
head -n 1 /dev/urandom | hexdump | head -n 1 | sed ‘s/0+| //g’ | sed ‘s/\(......\).*//g’
只需使用 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
八个 "random" 字母数字字符,只有 POSIX 工具箱?很好,一个挑战!
让我们从观察 Base-64 encoding uses almost only alphanumerics (and +
and /
) and the wonderful POSIX people have added Base-64 support with -m
to the uuencode 效用开始。
接下来,我们从哪里得到一些(pseudo?几乎?)随机性?再次观察当前进程列表是相当随意的,特别是如果它包含长格式的所有进程,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/^..\(........\).*//p'
kzNDkzMj
$ ps|cksum|uuencode -m -|sed -n 's,[+/],0,g; 2s/^..\(........\).*//p'
I0NTcxND
并将不需要的 +
和 /
转置为 0
。几乎可以保证每次调用都会得到不同的结果,因为三重管道中命令的进程 ID 与每个 运行 不同。
瞧!不需要 /dev/urandom
:-)