为什么在OSX上无法从/ dev / urandom读取tr?


35

一位同事建议通过以下命令创建随机密钥:

tr -dc A-Za-z0-9_\!\@\#\$\%\^\&\*\(\)-+= < /dev/urandom | head -c 32 | xargs

它给了我错误:

tr:非法字节序列

我担心/dev/urandom我的系统上没有。我尝试使用Google搜索来弄清楚如何安装此文件,但是我还是空着。我尝试过locate urandom,也空着出来。(实际上,它找到了手册页,但这无济于事)

如何urandom在Mac OSX系统上使用?(狮子)


3
有趣的使用xargs...
sendmoreinfo

Answers:


49

根据收到的错误消息,我认为/ dev / urandom不是问题。如果是这样,我希望会出现类似“没有这样的文件或目录”的错误。

我搜索了收到的错误消息,并发现了这个错误消息,这似乎与您的问题有关:http : //nerdbynature.de/s9y/2010/04/11/tr-Illegal-byte-sequence

基本上,通过在tr命令前添加来指定语言环境LC_CTYPE=C

LC_CTYPE=C tr -dc A-Za-z0-9_\!\@\#\$\%\^\&\*\(\)-+= < /dev/urandom | head -c 32 | xargs

谢谢,确实做到了。知道为什么我找不到urandomrandom吗?它们是在实际文件系统上不存在的特殊的神奇“文件”吗?(另外,我建议进行编辑以帮助缓解链接丢失)
Kirk Woll 2012年

1
我相信locate不会直接搜索您的文件系统,而是使用预建的数据库查找您的查询。该数据库很可能配置为忽略/ dev /和其他“特殊”文件系统。
lk-

足够公平,但是当我直接看时看不到它/dev。去搞清楚。但是再次感谢您的帮助。
Kirk Woll

1
似乎在10.9上不起作用;仍然失败,并显示相同的错误消息。LC_ALL=C做花招。
Erik Allik

1
请将该链接更改为nerdbynature.de/s9y/2010/04/11/tr-非法字节序列,因为当前该链接指向不包含该tr信息的最新博客页面。
Jeroen Wiert Pluimers'5

11

tr尝试将其输入解释为UTF-8编码的文本。因此它将抱怨并中止无效的UTF-8的第一个字节序列。trLC_ALL=C或加上前缀LC_CTYPE=C会将变量导出到的环境中tr,从而将其本地字符集的概念更改为C标准,即,所有内容只是一个不透明字节序列。

顺便说一句,\)-+您命令中的顺序是故意的吗?这也包括*您已经包含的内容,但不包括-您可能想要的本身。最好改写其中之一:

LC_ALL=C tr -dc 'A-Za-z0-9_!@#$%^&*()\-+=' < /dev/urandom
LC_CTYPE=C tr -dc A-Za-z0-9_\!\@\#\$\%\^\&\*\(\)\\-+= < /dev/urandom

6

正如其他人所指出的,你的问题不是/dev/urandom缺少,而是如何tr在OS X的作品而不是瞎搞与enviornment的varialbes,使用perl代替tr

perl -pe 'binmode(STDIN, ":bytes"); tr/A-Za-z0-9_\!\@\#\$\%\^\&\*\(\)-+=//dc;' < /dev/urandom | head -c 32; echo

这具有可跨OS X,Redhat和Ubuntu移植的优势。

(我还删除了到的管道xargs,替换了witch echo,以在输出末尾获得换行符。)


我希望Perl迟早会成为binmode ":utf8"标准,这时您的Perl解决方案就会遇到同样的问题tr
2015年

通过将binmode(STDIN,“:bytes”)添加到代码示例中,解决了Mark的问题。
特伦顿

2

首先,您打算将有效字符包含在列表中-还是将其包含*在列表中?要tr包含的参数的序列)-+表示“以开头)和结尾的字节范围+,实际上是)*+

其次,而不是从内核的熵池读千字节(并由此标志着整个池不安全的,这将影响需要安全的熵的任何其他进程),只考虑读书一样多的位,你需要:使用head -c...作为第一个步骤中,然后翻译而不是丢弃不需要的字符。

这个问题的特殊版本使用76个不同的符号,这有点不寻常。大多数人只想要字母数字,所以如果您只对64个符号感到满意,那么使用该base64实用程序将使熵池的消耗最小化(请注意,24是32的6/8):

head -c24 < /dev/random | base64

1

您的语言环境的字符编码(可以用来告诉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个字符)),因此tr在发生这种情况时返回错误。

您在这里想要的是将字节流视为编码中的每个字符一个字节的字符。无论你选择的是不是在你的范围内,因为所有重要的那些字符(由AZ假设,你的意思是像ABCDEFGHIJKLMNOPQRSTUVWXYZ而不是东西ÝÊ)是便携式的字符集,以便进行编码相同的所有支持系统上的字符集的一部分。

对于这一点,你会设置LC_CTYPE本地化变量,它是一个决定哪些字符集使用什么之类的东西blankalpha人物类包含。但是,对于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语言环境的字符集中表达俄语或日语错误消息)。


0

根据手册页,/ dev / random可能足以满足您的需求。也许苹果因为不必要而停止创建/ dev / urandom了?


我也没有/dev/random
柯克·沃尔

MacOSX应该同时具有/ dev / random和/ dev / urandom。也许苹果不再包含那些特殊文件了?或者也许只有安装XCode才在那里?
jsbillings

1
FWIW,这两个设备都在我的Lion升级到Mountain Lion工作站上。我相信它也存在于Lion上。节点也不同(13,0与
13,1
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.