Edición de secuencias binarias que contienen bytes '\ x00'

8

Usando solo herramientas de shell, ¿cómo se puede editar una secuencia binaria que contiene NULL (caracteres 0x00) manteniendo los caracteres 0x00 en la secuencia de salida?

La edición debe reemplazar un carácter en una posición especificada por otro carácter (en el siguiente ejemplo por el carácter '|'), como:

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

Pero sed está eliminando todos los caracteres '\ 0x00' antes del reemplazo.

EDITAR - Demostración del comportamiento de sed en mi entorno utilizando la prueba @George Vasiliou:

$ echo -e "lineA\nlineB\nlineC" | tr '\n' '\0' | 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' '\0' | sed 's/./|/5' | od -t x1
0000000 6c 69 6e 65 7c 6c 69 6e 65 42 6c 69 6e 65 43
0000017

Mi entorno es un AIX 7.1 y el sed que está allí no es la versión gnu.

Luciano
fuente

Respuestas:

10

sedes una utilidad de texto Funciona con líneas de texto (secuencias de caracteres no NUL (no bytes) de longitud limitada delimitados por un carácter de nueva línea).

Si desea cambiar la 2 ª y 5 ª byte de una secuencia de bytes, no va a funcionar por varias razones:

  • sedtrabaja en texto Si la entrada contiene caracteres NUL, no termina en un carácter de nueva línea, tiene más de LINE_MAX bytes entre dos caracteres de nueva línea, contiene secuencias de bytes que no forman caracteres válidos, dependiendo de la sedimplementación, no funcionará en todas. (tenga en cuenta que GNU sedno tiene muchas de esas limitaciones).
  • incluso si esa entrada binaria forma texto válido, .coincide con caracteres, no con bytes, por lo que puede coincidir con más de un byte.
  • debido a que el código sed se ejecuta para cada línea de la entrada, eso cambiaría el segundo y quinto carácter de cada línea, no de la entrada completa.

Para tratar la entrada como matrices arbitrarias de bytes (sin la limitación de bytes NUL o las limitaciones de longitud), puede usar perlen su lugar:

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

Ejemplo:

$ printf 'a\0b\0cd' |
>   perl -0777 -pe 'for $o (1, 4) {substr($_, $o, 1) = "|"}' |
>   od -Ax -tx1 -tc
000000  61  7c  62  00  7c  64
         a   |   b  \0   |   d
000006

O podría usar una representación de texto intermedio, como usar vimel xxdayudante de:

dd... | xxd -p | sed '1s/../7c/2;1s/../7c/5' | xxd -p -r

xxd -pda un volcado hexadecimal con 60 caracteres por línea de forma predeterminada. Arriba estamos reemplazando el segundo y quinto hexadecimal de 2 dígitos de la primera línea con 7cel número de ASCII |.

Stéphane Chazelas
fuente
Gracias. Estaba creando una solución alternativa usando xxd. Excelente ! Ambas soluciones funcionaron en AIX.
Luciano
1

Estás seguro ? con una prueba simple, esto no parece suceder en mi caso (gnu sed 4.2.2)

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

Con más pruebas, se perderá nulo si reemplaza el sexto carácter en mis pruebas (posición nula):

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

$ echo -e "lineA\nlineB\nlineC" |tr '\n' '\0' |sed 's/./|/7' |tr '\0' '\n'
lineA
|ineB           
lineC 
George Vasiliou
fuente
@Luciano Ver actualización
George Vasiliou
Mira mi edición
Luciano
@Luciano, también probé con sed --posix, que según mi manual deshabilita todas las extensiones de GNU, pero todavía hay bytes nulos presentes ...
George Vasiliou
Intenté sed en Linux, y sí parece estar funcionando. Pero necesito que funcione en AIX.
Luciano
1
@Luciano, claro, puedo entender esto ... Desafortunadamente, no tengo AIX para ayudarte, y hasta donde sé, parece que no hay AIX Shells en línea para jugar ... Estoy seguro de que la respuesta es El señor Chazelas te ayudará.
George Vasiliou
0

Pruebe bbe - sed clone para secuencias binarias: https://sourceforge.net/projects/bbe/

usuario280267
fuente
¿Podría agregar algunos detalles de soporte, como la forma en que el usuario en su entorno AIX podría usarlo? Además, tenga en cuenta que la pregunta dice "Usar solo herramientas de shell", por lo que es posible que no puedan compilar / instalar herramientas adicionales,
Jeff Schaller
¿Estás seguro de que estás vinculando a la herramienta correcta? Su enlace va a un proyecto de "Cifrado basado en bloque, también conocido como 2Bx4Bx2B", actualizado por última vez en 2013
Ale