Como armazenar um arquivo de imagem na variável bash?

14

Depois de usar o seguinte comando,

pngString="$(cat example.png)"    
echo -n "$pngString" > tmp.png

Não consigo abrir o tmp.png como um arquivo PNG. Talvez algumas informações sejam perdidas quando eu uso $pngStringpara armazenar o arquivo de imagem.

Portanto, a pergunta é: como posso armazenar as informações completas da imagem usando uma variável no script bash?

Libin Wen
fonte
O comando cat funciona bem (para armazenar os dados da imagem na variável). Basta remover as aspas duplas. A questão é o que você deseja fazer com esses dados depois de salvá-los na variável?
coffemug
5
cate echotodos os seus tipos estão no coração utilitários de texto . Soltá-los sem querer em arquivos binários terá resultados imprevisíveis. É por isso que coisas como base64foram inventadas.
Shadur
Por que você quer tê-lo como variável? As variáveis ​​do shell costumam armazenar pequena quantidade de texto, não grandes quantidades de dados binários. Nenhum dos shell usuais pode lidar com dados binários em variáveis ​​(eles engasgam com bytes nulos), exceto zsh.
Gilles 'SO- stop be evil'
Por que não apenas cat example.png > tmp.pngou melhor ainda cp example.png tmp.png?
Wildcard
@ Shahadur, catnão é realmente um utilitário de texto. É a substituição de comando (que retira as novas linhas à direita), a atribuição de variável (que não pode conter bytes nulos) e o echocomando (que pode interpretar as seqüências de barra invertida) que manipularão o binário, não cat. Mas eu concordo com o seu ponto de vista geral.
Wildcard

Respostas:

20

Você está certo nisso echoe a empresa não parece lidar bem com o binário. Suspeito que os caracteres nulos interrompam o fluxo muito cedo.

Você pode converter informações de imagem em algum formato baseado em ASCII. Por exemplo, isso é com base64:

$ pic=`base64 pic.jpeg`
$ echo $pic | base64 --decode > pic2.jpeg
$ diff pic*
$ echo $?
0
nperson325681
fonte
3
No meu sistema bash, tive que colocar a variável entre aspas, provavelmente porque a base64 pode conter espaço em branco: echo "$pic" | base64 --decode > pic2.jpeg
OldTimer
1

O problema é que bytes nulos não podem ser transmitidos através de argumentos de linha de comando, pois são usados ​​internamente como terminadores de argumento. Todos os outros bytes parecem estar bem. Portanto, uma alternativa um pouco mais eficiente em termos de espaço (normalmente) ao uso base64seria escapar dos bytes nulos e depois usá printf- los para converter os dados na forma original:

pngString="$(sed 's/\\/\\\\/g;s/%/%%/g;s/\x00/\\x00/g' <example.png)"
printf "$pngString" >tmp.png

Os caracteres \e %são especiais, printfentão eles precisam ser escapados também.

Observe também que, se os dados de entrada terminarem com uma nova linha, eles serão removidos pela substituição de comandos. Isso não deve ser um problema específico para PNGs, pois o último byte em um PNG válido deve ser 0x82, o byte menos significativo na IENDsoma do CRC do bloco vazio .

Karel Vlk
fonte
1
Se você quiser ainda mais barras invertidas, use: sed s/\\\\/\\\\\\\\/g\;s/%/%%/g\;s/\\x00/\\\\x00/g
Karel Vlk