OSXで/dev/urandomを読むことができないのはなぜですか?

OSXで/dev/urandomを読むことができないのはなぜですか?

同僚は、次のコマンドで任意のキーを作成することを提案しました。

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

エラーが発生します。

tr:無効なバイトシーケンス

私のシステムにないと思います/dev/urandom。このファイルをインストールする方法を見つけるためにインターネットを検索しようとしましたが、空の結果が出ました。私はそれを試しましたが、locate urandom何も得られませんでした。 (実際にマニュアルページを見つけましたが役に立ちませんでした)

urandomMac OSXシステムでどのように使用しますか? (ライオン)

答え1

/dev/urandomあなたが受け取ったエラーメッセージによると、これは問題ではないようです。その場合、同様のエラーが発生すると予想されますno such file or directory

あなたが受け取ったエラーメッセージを検索したところ、次のメッセージが見つかりました。これはあなたの問題に関連しているようです。nerdbynature.de 2010-04-11 tr-Illegal-byte-sequence (Web アーカイブの 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=CLC_CTYPE=Ctr

しかし、\)-+命令の順序は意図的なものですか?これには、*すでに含まれているが-必要に応じて含まれていないコンテンツも含まれます。次のように書くことをお勧めします。

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

答え3

他の人が指摘したように、問題は欠けているのではなく、OS Xで動作するようにする/dev/urandom方法です。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て魔女を交換して出力のecho末尾に改行文字を得ました。)

答え4

ロケールの文字エンコーディング(話すために使用できますlocale charmap)は、文字ごとに1マルチバイトです。

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

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

このランダムバイトストリームには無効なシーケンスが含まれている必要があるためです(たとえば、非ASCII文字は0xc1より大きいバイトで始まる必要があるため、0x80バイト自体はUTF-8では無効です(0xc0と0xc1は非UTF-8には存在しません)、trこの場合はエラーが返されます。

ここで望むのは、バイトストリームを1文字あたり1バイトのエンコーディングで文字として扱うことです。範囲内のすべての文字(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ロケールの文字セットで表現できません) 。

関連情報