web-dev-qa-db-ja.com

OSXで/ dev / urandomからtrを読み取れないのはなぜですか?

同僚は、次のコマンドを使用してランダムなキーを作成することを提案しました:

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

それは私にエラーを与えました:

tr:不正なバイトシーケンス

システムに/dev/urandomがないのではないかと心配です。このファイルをインストールする方法をグーグルで調べてみましたが、空になりました。私はlocate urandomを試しましたが、空っぽになりました。 (実際には、manページが見つかりましたが、それは役に立ちません)

Mac OSXシステムでurandomを利用できるようにするにはどうすればよいですか? (ライオン)

39
Kirk Woll

あなたが受け取るエラーメッセージに基づいて、私は/ 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
53
lk-

trは、入力をUTF-8エンコーディングのテキストとして解釈しようとします。そのため、有効なUTF-8ではない最初のバイトシーケンスでエラーが発生し、中断します。 trの前にLC_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
11
MvG

他の人が指摘したように、あなたの問題はそれではありません/dev/urandomがありませんが、OS Xでのtrの動作方法が異なります。環境変数をいじる代わりに、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を置き換えて、出力の最後で改行を取得しました。)

6
Trenton

まず、有効な文字のリストに-または*を含めるつもりでしたか? trのパラメーターには、シーケンス)-+が含まれています。これは、「)で始まり、+で終わるバイト範囲、実際には)*+です。

次に、カーネルのエントロピープールから数キロバイトを読み取る(つまり、プール全体を安全でないとマークし、安全なエントロピーを必要とする他のプロセスに影響を与える)のではなく、必要なビットだけを読み取ることを検討してください:head -c...を使用してくださいfirstステップとして、不要な文字を破棄するのではなく、翻訳します。

この問題のこの特定のバージョンは、76の異なるシンボルを使用するという点で少し変わっています。ほとんどの場合、英数字が必要なので、64シンボルだけで十分な場合は、base64ユーティリティを使用すると、エントロピープールの消費が最小限になります(24は32の6/8であることに注意してください)。

head -c24 < /dev/random | base64
2
Martin Kealey

ロケールの文字エンコーディング(locale charmapで確認できます)は、1文字あたりマルチバイトです。

現在最も一般的なのはUTF-8で、文字は1〜4バイトでエンコードできます。バイトのすべてのシーケンスがUTF-8で有効な文字を形成するわけではありません。 UTF-8のすべての非ASCII文字は、2つの最高ビットセットを持つ1バイトで始まり、最高(ただし2番目に高いビットではない)ビットセットを持つバイト数が続きます。

/dev/urandomには、ランダムなバイトストリームが含まれます。 trは文字を文字変換するため、これらのバイトを文字としてデコードする必要があります。これらのASCII=範囲内の文字はすべてUTF-8で1文字にエンコードされますが、trはすべての文字をデコードする必要があります。たとえば、他のマルチバイトエンコーディングがあります。ここで、A以外の一部の文字には0x41バイト(Aのコード)が含まれています。

そのランダムなバイトストリームは無効なシーケンスを含むようにバインドされているため(たとえば、ASCII以外の文字は0xc1より大きいバイトで始まる必要があるため、0x80バイト自体はUTF-8では無効です(0xc0および0xc1はUTF- 8文字))なので、trは、エラーが発生するとエラーを返します。

ここで必要なのは、1バイトが1文字であるエンコーディングのバイトストリームを文字として考えることです。範囲内のすべての文字(AZと仮定すると、ABCDEFGHIJKLMNOPQRSTUVWXYZを意味し、ÝÊなどではない)はポータブル文字セットの一部であるため、どちらを選択しても重要ではありません。システムでサポートされているすべての文字セット。

そのためには、使用する文字セットとblankalphaなどの文字クラスに含まれるものを決定するLC_CTYPEローカリゼーション変数を設定します。ただし、A〜Zの範囲を定義するには、LC_COLLATE変数(文字列の順序を決定する変数)も設定する必要があります。

C aka POSIXロケールは、文字がシングルバイトであることを保証するロケールであり、A-Zは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ロケールの文字セットでロシア語または日本語のエラーメッセージを表現する方法はありません)。

1

man page によると、おそらく/ dev/randomで十分です。おそらくAppleは不要なので/ dev/urandomの作成をやめましたか?

0
jsbillings