web-dev-qa-db-ja.com

ファイルを0xFFで埋めると、OSXでC3BFが得られます

このコマンドは、Linuxではファイルを0xffで埋めます。

dd if=/dev/zero ibs=1k count=100 | tr "\000" "\377" >paddedFile.bin

OSXで実行すると、結果が異なります。

$ dd if=/dev/zero ibs=1k count=100 | tr "\000" "\377" >paddedFile.bin
100+0 records in
200+0 records out
102400 bytes transferred in 0.000781 secs (131104008 bytes/sec)
$ hexdump -C paddedFile.bin
00000000  c3 bf c3 bf c3 bf c3 bf  c3 bf c3 bf c3 bf c3 bf  
|................|
*
00032000

何が起きてる?

4
Synesso

ポイントにまっすぐ。

これはすべて、実行時にターミナルセッションで設定されたLANGまたはLC_ALLの値に依存します tr 。 LinuxではそれらがCに設定されていますが、macOSではen_US.UTF-8のようなものに設定されています。もちろん、en_USen_UK(英国英語)などの他のローカル言語である可能性がありますが、ポイントは、プレーンASCII viaCがこれを引き起こしているのではなく[something].UTF-8設定です。

詳細。

MacOSの tr は、純粋なASCII 0xffの代わりに、c3bf0xffに相当するUTF8に変換しているようです。これについては this Appleコミュニティサポートスレッドはこちら

Linuxは、MacのようにターミナルでUnicodeを処理しません。 「LANG」環境変数を「C」に設定すると(おそらくLinux上にあるため)、機能します。それ以外の場合、これらの上位ビットはすべてUnicode文字として解釈されます。

そして、そのLANGヒントを使用すると機能します!次のようにしてください。私が今macOS10.13.6(High Sierra)で個人的にテストしました。

まず、既存のLANG値が次のようになっていることに注意してください。

echo $LANG

私が見る出力は次のとおりです。

en_US.UTF-8

次に、LANG値を次のようにCに設定します。

LANG=C

そして、そのコマンドを再度実行します。

dd if=/dev/zero ibs=1k count=100 | tr "\000" "\377" >paddedFile.bin

これで、hexdump値は次のようになります。

hexdump -C paddedFile.bin
00000000  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
*
00019000

LANG値をリセットするには、そのターミナルセッションを閉じるか、次のコマンドを実行します。

LANG=en_US.UTF-8

または、コメントで指摘されているように、次のようにLANGを呼び出す前に、コマンドラインオプションでtr値を直接設定できます。

dd if=/dev/zero ibs=1k count=100 | LANG=C tr "\000" "\377" >paddedFile.bin

また、LANGLC_ALLから派生しているため、LANGの代わりにLC_ALLを使用することもできます。

dd if=/dev/zero ibs=1k count=100 | LC_ALL=C tr "\000" "\377" >paddedFile.bin
9
JakeGould

問題は、Linux上にあるGNU trは、実際にはマルチバイト文字の概念を持っておらず、代わりに一度にバイト単位で機能することです。

tr man page およびオンラインドキュメントでは文字について説明していますが、これは少し単純化したものです。ソースコードパッケージのTODOファイルはこのアイテムに言及しています( coreutils 8. から選択):

Wc、tr、fmtなどのツール(ほとんどのtextutils)をマルチバイト対応に適合させます。問題は、ロジックの重要なブロックの重複を避けたいということですが、シングルバイトモードで動作する場合は最小限の(できれば「いいえ」)コストしか発生させたくないのです。

Linuxシステムでは、UTF-8ロケール(en_US.UTF-8)を使用している場合でも、GNU träを2つの「文字」として置き換えます(äのUTF-8表現は2バイトです)。

linux$ echo 'ä' | tr 'ä' 'x'
xx

同様に、äöを混在させると、UTF-8表現が共通のバイトを共有するため、面白い結果が得られます。

linux$ echo 'ö' | tr ä x
x�

またはその逆(xはここでは適用されません):

linux$ echo ab | tr ab äx
ä

そしてあなたの場合、GNU tr\377を生のバイト値として取ります。

Macのtrは異なり、マルチバイト文字の概念を認識しており、それに応じて動作します。

mac$ echo 'ä' | tr ä x
x

mac$ echo ab | tr ab äx
äx

数値0377(U + 00ff)の文字のUTF-8表現は2バイトc3 bfであるため、これが得られます。

trをバイトごとに機能させる簡単な方法は、UTF-8ロケールではなくCロケールを使用することです。これは再び面白い振る舞いをします:

$ echo 'ä' | LC_ALL=C tr 'ä' 'x'
xx

そしてあなたの場合、あなたは使用することができます:

... | LC_ALL=C tr "\000" "\377"

または、Perlのようなものを使用してそれらの\xffバイトを生成することもできます。

Perl -e 'printf "\377" x 1000 for 1..100'
5
ilkkachu