bash - por que \ x0d \ x20 apaga a linha

6

Esta é a visão do editor de gedit:

eavisãodoeditorvim:

Eu então tentei grep, ele fez grep com sucesso se eu colocar Log ao invés de Tog, mas a saída está corrompida:

[xiaobai@xiaobai grep]$ grep  Tog test
[xiaobai@xiaobai grep]$ grep  Log test
                               Dtring.valueOf
[xiaobai@xiaobai grep]$ 

E depois eu cato o arquivo, ele também está corrompido:

[xiaobai@xiaobai grep]$ cat test 
                               Dtring.valueOf
[xiaobai@xiaobai grep]$ 

Então eu uso o hexdump:

[xiaobai@xiaobai grep]$ hexdump -C test 
00000000  4c 6f 67 2e 64 28 22 6d  75 73 69 63 22 2c 20 22  |Log.d("music", "|
00000010  4e 41 56 49 47 41 54 4f  52 3a 20 22 20 2b 20 53  |NAVIGATOR: " + S|
00000020  74 72 69 6e 67 2e 76 61  6c 75 65 4f 66 0d 20 20  |tring.valueOf.  |
00000030  20 20 20 20 20 20 20 20  20 20 20 20 20 20 20 20  |                |
00000040  20 20 20 20 20 20 20 20  20 20 20 20 20 44 0d 0a  |             D..|
00000050
[xiaobai@xiaobai grep]$ 

Estou diminuindo:

[xiaobai@xiaobai grep]$ cat test3
                               D
[xiaobai@xiaobai grep]$ hexdump -C test3
00000000  61 0d 20 20 20 20 20 20  20 20 20 20 20 20 20 20  |a.              |
00000010  20 20 20 20 20 20 20 20  20 20 20 20 20 20 20 20  |                |
00000020  20 44 0d 0a                                       | D..|
00000024
[xiaobai@xiaobai grep]$ echo -e '\x61'
a
[xiaobai@xiaobai grep]$ echo -e '\x61\x0d'
a
[xiaobai@xiaobai grep]$ echo -e '\x61\x0d\x20'

[xiaobai@xiaobai grep]$ echo -e '\x61\x0d\x20\x62'
 b

Como você pode ver, o 'a' foi apagado depois que eu adicionei um byte \ x20.

Então, minha pergunta é: por que isso está acontecendo e como posso me livrar disso sem o conhecimento prévio de alguns arquivos que podem conter \ x0d \ x20, por exemplo, grep -r?

    
por 林果皞 08.05.2015 / 14:08

2 respostas

15

Caracteres do código 0 a 31 em ASCII são caracteres de controle. Quando enviados para um terminal, costumam fazer coisas especiais. Por exemplo, \a (BEL, 0x7) toca a campainha do terminal. \b (BS, 0x8) move o cursor para trás. \n (LF, 0xa) move o cursor uma linha para baixo, \t (TAB 0x9) move o cursor para a próxima tabulação ...

\r (CR, 0xd) move o cursor para a primeira coluna.

Quando você executa em um prompt do shell em um terminal:

printf 'foo\nbar\n'

printf escreve foo\nbar\n para /dev/tty<something> , a disciplina de linha tty desse dispositivo traduz isso para foo\r\nbar\r\n , e é por isso que você vê bar na próxima linha depois de foo .

printf 'foo\rbar\n'

O terminal teria que sobrescrever foo com bar .

Se o seu arquivo contiver caracteres de controle, você poderá removê-los ou dar a eles uma representação textual (por exemplo ^M ou \r para o caractere CR 0xd) se você quiser verificar a presença deles.

Você pode não querer fazer isso para os caracteres LF e TAB. Então:

LC_ALL=C tr -d '
LC_ALL=C sed "$(printf 's/[^\t -60-7]/^&/g')" < file |
  LC_ALL=C tr '
printf 'foo\nbar\n'
--7' '@-HK-_?'
--7' < file # to remove them cat -v < file # to display as ^M sed -n l < file # to display as \r (also converts TAB to \t) # and marks the end of lines with $

Observe que os sed e cat também transformariam caracteres não ASCII. Você poderia fazer em vez disso:

printf 'foo\rbar\n'

Para converter somente os caracteres de controle ASCII (exceto TAB e LF) para sua forma visual ^X (note que nem todas as implementações de sed suportam arquivos de entrada com caracteres NUL).

    
por 08.05.2015 / 14:23
4

\x0d é o caractere \r que traz o cursor para o início da linha e, em seguida, \x20 é um espaço, portanto, substitui o a por um espaço. Se você estiver em um sistema unix-y, você pode querer considerar apenas remover \r de sua saída / arquivo, já que não é necessário se for para saída de texto. O \n "implica" para * nix, mas não para o Windows.

    
por 08.05.2015 / 14:19