Lidar com dados binários em um nível baixo em shell scripts geralmente é uma má idéia.
bash
variables não podem conter o byte 0. zsh
é o único shell que pode armazenar esse byte em suas variáveis.
Em qualquer caso, argumentos de comando e variáveis de ambiente não podem conter esses bytes, pois são strings delimitadas por NUL transmitidas à chamada de sistema execve
.
Observe também que:
var='cmd'
ou sua forma moderna:
var=$(cmd)
retira todos os caracteres de nova linha à direita da saída de cmd
. Então, se a saída binária terminar em 0xa bytes, ela será desconfigurada quando armazenada em $var
.
Aqui, você precisa armazenar os dados codificados, por exemplo, com xxd -p
.
hdr_988=$(head -c 988 < "$inputFile" | xxd -p)
printf '%s\n' "$hdr_988" | xxd -p -r > "$output_hdr"
Você pode definir funções 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
output não é eficiente em termos de espaço, pois codifica 1 byte em 2 bytes, mas facilita a manipulação com ele (concatenando, extraindo partes). base64
é aquele que codifica 3 bytes em 4, mas não é tão fácil de trabalhar.
O shell ksh93
tem um formato de codificação incorporado (usa base64
) que você pode usar com seus utilitários read
e printf
/ print
:
typeset -b var # marked as "binary"/"base64-encoded"
IFS= read -rn 988 var < input
printf %B var > output
Agora, se não houver trânsito por meio de variáveis shell ou env, ou argumentos de comando, você deverá estar OK, desde que os utilitários utilizados possam manipular qualquer valor de byte. Mas note que, para utilitários de texto, a maioria das implementações não-GNU não pode manipular bytes NUL, e você vai querer corrigir o código de idioma para C para evitar problemas com caracteres multi-byte. O último caractere que não é um caractere de nova linha também pode causar problemas, bem como linhas muito longas (seqüências de bytes entre dois bytes de 0xa que são maiores que LINE_MAX
).
head -c
onde está disponível deve estar OK aqui, já que funciona com bytes e não tem motivos para tratar os dados como texto. Então
head -c 988 < input > output
deve estar OK. Na prática, pelo menos, as implementações embutidas GNU, FreeBSD e ksh93 estão OK. POSIX não especifica a opção -c
, mas diz que head
deve suportar linhas de qualquer tamanho (não limitado a LINE_MAX
)
com zsh
:
IFS= read -rk988 -u0 var < input &&
print -rn -- $var > output
Ou:
var=$(head -c 988 < input && echo .) && var=${var%.}
print -rn -- $var > output
Mesmo em zsh
, se $var
contiver bytes NUL, você pode passá-lo como argumento para zsh
builtins (como print
acima) ou funções, mas não como argumentos para executáveis, como argumentos passados para executáveis são strings delimitadas por NUL, que é uma limitação do kernel, independente do shell.