Modification de flux binaires contenant des octets '\ x00'

8

En utilisant uniquement des outils shell, comment un flux binaire contenant des NULL (caractères 0x00) peut-il être modifié en conservant les caractères 0x00 dans le flux de sortie?

L'édition doit remplacer un caractère dans une position spécifiée pour un autre caractère (dans l'exemple suivant par le caractère '|'), comme:

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

Mais sed supprime tous les caractères '\ 0x00' avant le remplacement.

EDIT - Démonstration du comportement des sed dans mon environnement à l'aide du test @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

Mon environnement est un AIX 7.1 et le sed qui s'y trouve n'est pas la version gnu.

Luciano
la source

Réponses:

10

sedest un utilitaire de texte . Il fonctionne avec des lignes de texte (séquences de caractères non NUL (pas d'octets) de longueur limitée délimités par un caractère de nouvelle ligne).

Si vous souhaitez modifier les 2 e et 5 e octets d'une séquence d'octets, cela ne fonctionnera pas pour plusieurs raisons:

  • sedfonctionne sur du texte. Si l'entrée contient des caractères NUL, ne se termine pas par un caractère de nouvelle ligne, a plus de LINE_MAX octets entre deux caractères de nouvelle ligne, contient des séquences d'octets qui ne forment pas de caractères valides, selon l' sedimplémentation, cela ne fonctionnera pas à tout. (notez que GNU sedn'a pas beaucoup de ces limitations).
  • même si cette entrée binaire se trouve former un texte valide, .correspond à des caractères et non à des octets, elle peut donc correspondre à plusieurs octets.
  • parce que le code sed est exécuté pour chaque ligne de l'entrée, cela changerait le deuxième et le cinquième caractère de chaque ligne, pas de l'entrée entière.

Pour traiter l'entrée comme des tableaux d'octets arbitraires (sans la limitation d'octet NUL ou les limitations de longueur), vous pouvez utiliser à la perlplace:

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

Exemple:

$ 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

Ou vous pouvez utiliser une représentation de texte intermédiaire, comme l'aide vimde l' xxdaide:

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

xxd -pdonne un vidage hexadécimal avec 60 caractères par ligne par défaut. Ci-dessus, nous remplaçons le deuxième et le cinquième hexadécimal à deux chiffres de la première ligne par 7c, le numéro pour ASCII |.

Stéphane Chazelas
la source
Merci. Je construisais une solution de contournement en utilisant xxd. Génial ! Les deux solutions fonctionnaient sous AIX.
Luciano
1

Êtes-vous sûr ? avec un simple test cela ne semble pas se produire dans mon cas (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

Avec d'autres tests, null sera perdu si vous remplacez le 6ème caractère dans mes tests (position null):

$ 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
la source
@Luciano Voir la mise à jour
George Vasiliou
Regardez mon montage
Luciano
@ Luciano, j'ai aussi essayé avec sed --posix qui selon mon manuel désactive toutes les extensions GNU, mais des octets nuls sont toujours présents ....
George Vasiliou
J'ai essayé sed sous Linux, et oui semble fonctionner. Mais je dois le faire fonctionner sous AIX.
Luciano
1
@ Luciano, bien sûr, je peux comprendre cela ... Malheureusement, je n'ai pas AIX pour vous aider, et pour autant que je sache, il ne semble pas y avoir d'AIX Shells en ligne pour jouer avec ... Je suis sûr que la réponse de M. Chazelas vous aidera.
George Vasiliou
0

Essayez le clone bbe-sed pour les flux binaires: https://sourceforge.net/projects/bbe/

user280267
la source
Pourriez-vous ajouter des détails de prise en charge, tels que la façon dont l'utilisateur dans son environnement AIX pourrait l'utiliser? Notez également que la question dit "Utiliser uniquement des outils shell", de sorte qu'ils peuvent être empêchés de compiler / installer des outils supplémentaires,
Jeff Schaller
Êtes-vous sûr de créer un lien vers le bon outil? Votre lien va à un projet "Block Based Encryption aka 2Bx4Bx2B" mis à jour pour la dernière fois en 2013
Ale