Editando fluxos binários contendo '\ x00' bytes

8

Usando apenas ferramentas shell, como um fluxo binário contendo NULLs (0x00 chars) pode ser editado mantendo os caracteres 0x00 no fluxo de saída?

A edição precisa substituir um caractere em uma posição especificada por outro caractere (no exemplo a seguir pelo caractere '|'), como:

dd ibs=1 skip=$offset count=$reglen status=none if=$ARQ |
        sed 's/./\|/2' |
        sed 's/./\|/5' #| more replacements....

Mas o sed está removendo todos os caracteres '\ 0x00' antes da substituição.

EDIT - Demonstração do comportamento sed no meu ambiente usando o teste @George Vasiliou:

$ echo -e "lineA\nlineB\nlineC" | tr '\n' '
dd ibs=1 skip=$offset count=$reglen status=none if=$ARQ |
        sed 's/./\|/2' |
        sed 's/./\|/5' #| more replacements....
' | od -t x1 0000000 6c 69 6e 65 41 00 6c 69 6e 65 42 00 6c 69 6e 65 0000020 43 00 0000022 $ echo -e "lineA\nlineB\nlineC" | tr '\n' '
$ echo -e "lineA\nlineB\nlineC" | tr '\n' '%pre%' | od -t x1
0000000 6c 69 6e 65 41 00 6c 69 6e 65 42 00 6c 69 6e 65
0000020 43 00
0000022

$ echo -e "lineA\nlineB\nlineC" | tr '\n' '%pre%' | sed 's/./|/5' | od -t x1
0000000 6c 69 6e 65 7c 6c 69 6e 65 42 6c 69 6e 65 43
0000017
' | sed 's/./|/5' | od -t x1 0000000 6c 69 6e 65 7c 6c 69 6e 65 42 6c 69 6e 65 43 0000017

Meu ambiente é um AIX 7.1 e o sed que está lá não é a versão do gnu.

    
por Luciano 20.02.2017 / 13:18

3 respostas

9

sed é um utilitário texto . Ele trabalha com linhas de texto (seqüências de caracteres não-NUL (não bytes) de tamanho limitado delimitados por um caractere de nova linha).

Se você quiser alterar os 2 nd e 5 th byte de uma seqüência de bytes, ele não funcionará por vários motivos :

  • sed funciona no texto. Se a entrada contiver caracteres NUL, não terminará em um caractere de nova linha, terá mais de LINE_MAX bytes entre dois caracteres de nova linha, conterá sequências de bytes que não formam caracteres válidos, dependendo da implementação sed , ganhou ' t trabalho em tudo. (note que o GNU sed não possui muitas dessas limitações).
  • mesmo se essa entrada binária formar um texto válido, . corresponderá a caracteres, não a bytes, portanto, poderá corresponder a mais de um byte.
  • porque o código sed é executado para cada linha da entrada, que mudaria o segundo e quinto caractere de cada linha, não da entrada inteira.

Para tratar entradas como matrizes arbitrárias de bytes (sem a limitação de bytes NUL ou limitações de tamanho), você pode usar perl :

 dd.... | perl -0777 -pe 'for $o (1, 4) {substr($_, $o, 1) = "|"}'

Exemplo:

$ printf 'a
dd... | xxd -p | sed '1s/../7c/2;1s/../7c/5' | xxd -p -r
b
 dd.... | perl -0777 -pe 'for $o (1, 4) {substr($_, $o, 1) = "|"}'
cd' | > perl -0777 -pe 'for $o (1, 4) {substr($_, $o, 1) = "|"}' | > od -Ax -tx1 -tc 000000 61 7c 62 00 7c 64 a | b
$ printf 'a
dd... | xxd -p | sed '1s/../7c/2;1s/../7c/5' | xxd -p -r
b%pre%cd' | > perl -0777 -pe 'for $o (1, 4) {substr($_, $o, 1) = "|"}' | > od -Ax -tx1 -tc 000000 61 7c 62 00 7c 64 a | b %pre% | d 000006
| d 000006

Ou você pode usar uma representação de texto intermediário, como usar vim ' xxd helper:

%pre%

xxd -p fornece um dump hexadecimal com 60 caracteres por linha, por padrão. Acima estamos substituindo o segundo e quinto hex de 2 dígitos da primeira linha com 7c , o número para ASCII | .

    
por 20.02.2017 / 13:48
2

Tem certeza? com um teste simples, isso não parece acontecer no meu caso (gnu 4.2.2)

$ echo -e "lineA\nlineB\nlineC"
lineA
lineB
lineC
$ echo -e "lineA\nlineB\nlineC" |tr '\n' '
$ echo -e "lineA\nlineB\nlineC" |tr '\n' '
$ echo -e "lineA\nlineB\nlineC"
lineA
lineB
lineC
$ echo -e "lineA\nlineB\nlineC" |tr '\n' '
$ echo -e "lineA\nlineB\nlineC" |tr '\n' '%pre%' |sed 's/./|/6' |tr '%pre%' '\n'
lineA|lineB 
lineC

$ echo -e "lineA\nlineB\nlineC" |tr '\n' '%pre%' |sed 's/./|/7' |tr '%pre%' '\n'
lineA
|ineB           
lineC 
' lineAlineBlineC $ echo -e "lineA\nlineB\nlineC" |tr '\n' '%pre%' |sed 's/./|/5' line|lineBlineC # Verification if the nulls are still there: $ echo -e "lineA\nlineB\nlineC" |tr '\n' '%pre%' |sed 's/./|/5' |tr '%pre%' '\n' line| lineB lineC
' |sed 's/./|/6' |tr '%pre%' '\n' lineA|lineB lineC $ echo -e "lineA\nlineB\nlineC" |tr '\n' '%pre%' |sed 's/./|/7' |tr '%pre%' '\n' lineA |ineB lineC
' lineAlineBlineC $ echo -e "lineA\nlineB\nlineC" |tr '\n' '%pre%' |sed 's/./|/5' line|lineBlineC # Verification if the nulls are still there: $ echo -e "lineA\nlineB\nlineC" |tr '\n' '%pre%' |sed 's/./|/5' |tr '%pre%' '\n' line| lineB lineC

Com mais testes, null será perdido se você substituir o 6º caractere em meus testes (posição nula):

%pre%     
por 20.02.2017 / 13:38
0

Experimente o clone bbe - sed para fluxos binários: link

    
por 12.03.2018 / 18:10

Tags