一位同事建议通过以下命令创建随机密钥:
tr -dc A-Za-z0-9_\!\@\#\$\%\^\&\*\(\)-+= < /dev/urandom | head -c 32 | xargs
它给了我错误:
tr:非法字节序列
我担心我的系统上没有/dev/urandom
。我尝试用谷歌搜索来找出如何安装这个文件,但结果却是空的。我尝试了一下locate urandom
,也一无所获。 (实际上,它找到了手册页,但这没有帮助)
如何urandom
在我的 Mac OSX 系统上使用? (狮子)
答案1
根据您收到的错误消息,我认为/dev/urandom
这不是问题。如果是的话,我预计会出现类似的错误no such file or directory
。
我搜索了您收到的错误消息并发现了此消息,这似乎可能与您的问题相关:nerdbynature.de 2010-04-11 tr-Illegal-byte-sequence(Web Archive 的 2019-09 快照)
tr
基本上,通过在命令前面添加LC_CTYPE=C
(或LC_ALL=C
,请参阅注释)来指定区域设置:
LC_CTYPE=C tr -dc A-Za-z0-9_\!\@\#\$\%\^\&\*\(\)-+= < /dev/urandom | head -c 32 | xargs
答案2
您tr
尝试将其输入解释为 UTF-8 编码的文本。因此,它会抱怨并中止第一个字节序列不是有效的 UTF-8。前缀或会tr
将该变量导出到 的环境中,从而将其本地字符集的想法更改为 C 标准,即一切都只是不透明字节的序列。LC_ALL=C
LC_CTYPE=C
tr
顺便问一下,\)-+
你的命令中的序列是故意的吗?这*
也包括你已经包括的内容,但没有-
像你希望的那样包括它自己。最好写一个这样的:
LC_ALL=C tr -dc 'A-Za-z0-9_!@#$%^&*()\-+=' < /dev/urandom
LC_CTYPE=C tr -dc A-Za-z0-9_\!\@\#\$\%\^\&\*\(\)\\-+= < /dev/urandom
答案3
正如其他人所指出的,您的问题不是/dev/urandom
缺少,而是如何tr
在 OS X 上工作。不要乱搞环境变量,而是使用perl
以下内容tr
:
perl -pe 'binmode(STDIN, ":bytes"); tr/A-Za-z0-9_\!\@\#\$\%\^\&\*\(\)-+=//dc;' < /dev/urandom | head -c 32; echo
其优点是可以跨 OS X、Redhat 和 Ubuntu 移植。
(我还删除了管道xargs
,替换 女巫echo
,以在输出末尾获得换行符。)
答案4
您的语言环境的字符编码(您可以使用 来判断locale charmap
)是每个字符一个多字节。
如今最常见的是 UTF-8,其中字符可以编码为 1 到 4 个字节。并非所有字节序列都会形成 UTF-8 中的有效字符。 UTF-8 中的每个非 ASCII 字符都以设置了两个最高位的一个字节开始,并说明后面有多少个设置了最高位(但不是第二高位)的字节。
/dev/urandom
包含随机字节流。tr
音译字符,因此需要将这些字节解码为字符。您范围内的那些 ASCII 字符均以 UTF-8 编码在一个字符上,但tr
仍需要对所有字符进行解码。例如,还有其他多字节编码,其中某些字符不A
包含 0x41 字节( 的代码A
)。
因为该随机字节流必然包含无效序列(例如,0x80 字节本身在 UTF-8 中是无效的,因为非 ASCII 字符必须以大于 0xc1 的字节开头(0xc0 和 0xc1 在非 UTF-8 中不存在) 8 个字符)),因此tr
当发生这种情况时会返回错误。
这里您想要的是将字节流视为每个字符一个字节的编码中的字符。无论您选择哪个并不重要,因为您范围内的所有这些字符(假设 AZ,您的意思是 ABCDEFGHIJKLMNOPQRSTUVWXYZ 而不是诸如Ý
,之类的Ê
字符)都是可移植字符集的一部分,因此在系统支持的所有字符集中进行相同的编码。
为此,您需要设置LC_CTYPE
本地化变量,该变量决定使用哪种字符集以及字符类包含哪些blank
内容alpha
。但对于 AZ 范围的定义,您还需要设置变量LC_COLLATE
(决定字符串排序的变量)。
C
又名区域设置POSIX
是保证字符为单字节且 AZ 为 ABCDEFGHIJKLMNOPQRSTUVWXYZ 的区域设置。你可以这样做:
LC_CTYPE=C LC_COLLATE=C tr -dc 'A-Za-z0-9_!@#$%^&*()+=-'
(这里将 移动-
到末尾,否则)-+
将被视为一个范围,如A-Z
)
但请注意,LC_ALL
变量会覆盖所有其他LC_*
和LANG
变量。因此,如果LC_ALL
已经定义,则上述操作将不起作用。因此,您可以简单地执行以下操作:
LC_ALL=C tr -dc 'A-Za-z0-9_!@#$%^&*()+=-'
这会影响其他事情,例如错误消息的语言,但无论如何,更改 LC_CTYPE 可能已经成为错误消息的问题(例如,无法在 C 语言环境的字符集中表达俄语或日语错误消息)。