Traiter des données binaires à un bas niveau dans les scripts shell est généralement une mauvaise idée.
bash
les variables ne peuvent pas contenir l'octet 0. zsh
est le seul shell qui peut stocker cet octet dans ses variables.
Dans tous les cas, les arguments de commande et les variables d'environnement ne peuvent pas contenir ces octets car ce sont des chaînes délimitées NUL passées à l' execve
appel système.
Notez également que:
var=`cmd`
ou sa forme moderne:
var=$(cmd)
supprime tous les caractères de nouvelle ligne de fin de la sortie de cmd
. Donc, si cette sortie binaire se termine par 0xa octets, elle sera altérée lorsqu'elle sera stockée dans $var
.
Ici, vous devez stocker les données encodées, par exemple avec xxd -p
.
hdr_988=$(head -c 988 < "$inputFile" | xxd -p)
printf '%s\n' "$hdr_988" | xxd -p -r > "$output_hdr"
Vous pouvez définir des fonctions d'assistance comme:
encode() {
eval "$1"='$(
shift
"$@" | xxd -p -c 0x7fffffff
exit "${PIPESTATUS[0]}")'
}
decode() {
printf %s "$1" | xxd -p -r
}
encode var cat /bin/ls &&
decode "$var" | cmp - /bin/ls && echo OK
xxd -p
la sortie n'est pas efficace en termes d'espace car elle code 1 octet en 2 octets, mais elle facilite les manipulations avec elle (concaténation, extraction de parties). base64
est celui qui code 3 octets en 4, mais n'est pas aussi facile à utiliser.
Le ksh93
shell a un format de codage intégré (utilise base64
) que vous pouvez utiliser avec ses utilitaires read
et printf
/ print
:
typeset -b var # marked as "binary"/"base64-encoded"
IFS= read -rn 988 var < input
printf %B var > output
Maintenant, s'il n'y a pas de transit via des variables shell ou env, ou des arguments de commande, vous devriez être OK tant que les utilitaires que vous utilisez peuvent gérer n'importe quelle valeur d'octet. Mais notez que pour les utilitaires de texte, la plupart des implémentations non GNU ne peuvent pas gérer les octets NUL, et vous voudrez corriger les paramètres régionaux en C pour éviter les problèmes avec les caractères multi-octets. Le dernier caractère n'étant pas un caractère de nouvelle ligne peut également provoquer des problèmes ainsi que des lignes très longues (séquences d'octets entre deux octets 0xa qui sont plus longs LINE_MAX
).
head -c
où il est disponible devrait être OK ici, car il est censé fonctionner avec des octets, et n'a aucune raison de traiter les données comme du texte. Donc
head -c 988 < input > output
ça devrait être bon. En pratique, au moins les implémentations intégrées GNU, FreeBSD et ksh93 sont OK. POSIX ne spécifie pas l' -c
option, mais indique qu'il head
devrait prendre en charge les lignes de n'importe quelle longueur (sans s'y limiter LINE_MAX
)
Avec zsh
:
IFS= read -rk988 -u0 var < input &&
print -rn -- $var > output
Ou:
var=$(head -c 988 < input && echo .) && var=${var%.}
print -rn -- $var > output
Même dans zsh
, s'il $var
contient des octets NUL, vous pouvez le passer comme argument aux commandes zsh
internes (comme print
ci-dessus) ou aux fonctions, mais pas comme arguments aux exécutables, car les arguments passés aux exécutables sont des chaînes délimitées par NUL, c'est une limitation du noyau, indépendante du shell.
dd
pour copier des octets individuels (en le définissantcount
sur1
). Je ne suis pas sûr de les stocker, cependant.