Tratar con datos binarios a un nivel bajo en scripts de shell es generalmente una mala idea.
bash
las variables no pueden contener el byte 0. zsh
es el único shell que puede almacenar ese byte en sus variables.
En cualquier caso, los argumentos de comando y las variables de entorno no pueden contener esos bytes, ya que son cadenas delimitadas por NUL que se pasan a la execve
llamada del sistema.
También tenga en cuenta que:
var=`cmd`
o su forma moderna:
var=$(cmd)
elimina todos los caracteres de nueva línea finales de la salida de cmd
. Entonces, si esa salida binaria termina en 0xa bytes, se destruirá cuando se almacene en $var
.
Aquí, necesitaría almacenar los datos codificados, por ejemplo con xxd -p
.
hdr_988=$(head -c 988 < "$inputFile" | xxd -p)
printf '%s\n' "$hdr_988" | xxd -p -r > "$output_hdr"
Podría definir funciones auxiliares como:
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 salida no es eficiente en cuanto al espacio, ya que codifica 1 byte en 2 bytes, pero hace que sea más fácil hacer manipulaciones con ella (concatenación, extracción de partes). base64
es uno que codifica 3 bytes en 4, pero no es tan fácil trabajar con él.
El ksh93
shell tiene un formato de codificación incorporado (usos base64
) que puede usar con sus read
y printf
/ print
utilidades:
typeset -b var # marked as "binary"/"base64-encoded"
IFS= read -rn 988 var < input
printf %B var > output
Ahora, si no hay tránsito a través de variables de shell o env, o argumentos de comando, debe estar bien siempre que las utilidades que use puedan manejar cualquier valor de byte. Pero tenga en cuenta que para las utilidades de texto, la mayoría de las implementaciones que no son GNU no pueden manejar bytes NUL, y querrá arreglar la configuración regional en C para evitar problemas con los caracteres de varios bytes. El último carácter que no es un carácter de nueva línea también puede causar problemas, así como líneas muy largas (secuencias de bytes entre dos bytes 0xa más largos LINE_MAX
).
head -c
donde esté disponible debería estar bien aquí, ya que está destinado a trabajar con bytes y no tiene ninguna razón para tratar los datos como texto. Entonces
head -c 988 < input > output
debería estar bien. En la práctica, al menos las implementaciones incorporadas de GNU, FreeBSD y ksh93 están bien. POSIX no especifica la -c
opción, pero dice que head
debería admitir líneas de cualquier longitud (no limitado a LINE_MAX
)
Con zsh
:
IFS= read -rk988 -u0 var < input &&
print -rn -- $var > output
O:
var=$(head -c 988 < input && echo .) && var=${var%.}
print -rn -- $var > output
Incluso en el zsh
caso de que $var
contenga bytes NUL, puede pasarlo como argumento a las zsh
funciones incorporadas (como print
arriba) o funciones, pero no como argumentos a los ejecutables, ya que los argumentos pasados a los ejecutables son cadenas delimitadas por NUL, eso es una limitación del núcleo, independiente del shell.
dd
para copiar bytes individuales (estableciendo sucount
en1
). Sin embargo, no estoy seguro de almacenarlos.