O arquivo de preenchimento com 0xFF fornece o C3BF no OSX

4

Este comando preencherá o arquivo com 0xff no Linux.

dd if=/dev/zero ibs=1k count=100 | tr "
$ dd if=/dev/zero ibs=1k count=100 | tr "
dd if=/dev/zero ibs=1k count=100 | tr "
$ dd if=/dev/zero ibs=1k count=100 | tr "%pre%0" "7" >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
0" "7" >paddedFile.bin
0" "7" >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
0" "7" >paddedFile.bin

Quando eu executo no OSX, os resultados são diferentes.

%pre%

O que está acontecendo aqui?

    
por Synesso 16.08.2018 / 05:35

2 respostas

9

Direto ao ponto.

Tudo depende do valor LANG ou LC_ALL definido na sua sessão de terminal quando você executa tr . O Linux os definiu como C , enquanto o macOS definiu como en_US.UTF-8 . É claro que en_US poderia ser algum outro idioma local como en_UK (inglês do Reino Unido), mas o ponto é a configuração [something].UTF-8 em vez de ASCII simples via C é o que está causando isso.

Mais detalhes.

Parece que o tr no macOS está convertendo o 0xff no equivalente a UTF8 de c3bf quando Obtém em vez do puro ASCII 0xff . Isso é explicado aqui no este tópico de suporte da comunidade da Apple :

Linux doesn't handle Unicode in the Terminal like the Mac does. If you set the "LANG" environment variable to "C" (as it probably is on Linux), it will work. Otherwise, all those high-order bits are going to get interpreted as Unicode characters.

E usando esse LANG tip funciona! Apenas faça o seguinte; testado pessoalmente por mim só agora no macOS 10.13.6 (High Sierra).

Primeiro, tome nota de como o valor LANG existente é assim:

echo $LANG

A saída que vejo é:

en_US.UTF-8

Agora defina o valor LANG como C da seguinte forma:

LANG=C

E execute o comando novamente:

dd if=/dev/zero ibs=1k count=100 | tr "
hexdump -C paddedFile.bin
00000000  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
*
00019000
0" "7" >paddedFile.bin

Agora, os valores de hexdump devem ficar assim:

LANG=en_US.UTF-8

Para redefinir o valor LANG , feche a sessão do terminal ou apenas execute este comando:

dd if=/dev/zero ibs=1k count=100 | LANG=C tr "
dd if=/dev/zero ibs=1k count=100 | LC_ALL=C tr "
echo $LANG
0" "7" >paddedFile.bin
0" "7" >paddedFile.bin

Ou - como apontado nos comentários - você pode definir o valor LANG diretamente nas opções da linha de comando antes de chamar tr da seguinte forma:

en_US.UTF-8

E você ainda pode usar LC_ALL em vez de LANG porque LANG é derivado de LC_ALL assim:

LANG=C
    
por 16.08.2018 / 06:00
4

O problema é que o GNU tr , que você tem no Linux, não tem realmente um conceito de caracteres multibyte, mas funciona byte de cada vez.

A tr man page e a documentação on-line falam de caracteres, mas isso é um pouco simplificador. O arquivo TODO no pacote de código-fonte menciona este item (escolhido de coreutils 8.30 ):

Adapt tools like wc, tr, fmt, etc. (most of the textutils) to be multibyte aware. The problem is that I want to avoid duplicating significant blocks of logic, yet I also want to incur only minimal (preferably 'no') cost when operating in single-byte mode.

Em um sistema Linux - mesmo com uma localidade UTF-8 ( en_US.UTF-8 ) - o GNU tr substitui um ä como dois "caracteres" (a representação UTF-8 de ä tem dois bytes):

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

Na mesma linha, misturar um ä e um ö produz resultados engraçados, pois suas representações UTF-8 compartilham um byte comum:

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

Ou o contrário (o x não se aplica aqui):

linux$ echo ab | tr ab äx
ä

E no seu caso, o GNU tr usa o 7 como um valor bruto de byte.

O tr no Mac é diferente, conhece o conceito de caracteres multibyte e age de acordo:

mac$ echo 'ä' | tr ä x
x

mac$ echo ab | tr ab äx
äx

A representação UTF-8 do caractere com o valor numérico 0377 (U + 00ff) são os dois bytes c3 bf , então é isso que você obtém.

A maneira fácil de ter tr work byte-by-by é usar o local C, em vez de um código do idioma UTF-8. Isso dá o comportamento engraçado novamente:

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

E no seu caso, você pode usar:

... | LC_ALL=C tr "
perl -e 'printf "7" x 1000 for 1..100'
0" "7"

Ou você poderia usar algo como Perl para gerar esses \xff bytes:

linux$ echo 'ä' | tr 'ä' 'x'
xx
    
por 16.08.2018 / 21:41

Tags