¿Cómo almacenar un archivo de imagen en bash variable?

14

Después de usar el siguiente comando,

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

No puedo abrir el archivo tmp.png como un archivo PNG. Tal vez se pierde algo de información cuando uso $pngStringpara almacenar el archivo de imagen.

Entonces la pregunta es: ¿cómo puedo almacenar la información de imagen completa usando una variable en script bash?

Libin Wen
fuente
El comando cat funciona bien (para almacenar los datos de la imagen en la variable). Simplemente elimine las comillas dobles. La pregunta es ¿qué desea hacer con estos datos después de guardarlos en la variable?
coffeMug
55
caty echotodo lo demás son utilidades de texto en el fondo . Dejarlos soltar desprevenidos en archivos binarios tendrá resultados impredecibles. Por eso base64se inventaron cosas como .
Shadur
¿Por qué quieres tenerlo como variable? Las variables de shell generalmente están destinadas a almacenar una pequeña cantidad de texto, no grandes cantidades de datos binarios. Ninguno de los shell habituales puede hacer frente a datos binarios en variables (se ahogan en bytes nulos) excepto zsh.
Gilles 'SO- deja de ser malvado'
¿Por qué no solo cat example.png > tmp.pngo mejor aún cp example.png tmp.png?
Comodín
@Shadur, catno es realmente una utilidad de texto. Es la sustitución de comandos (que elimina las nuevas líneas finales), la asignación de variables (que no puede contener bytes nulos) y el echocomando (que puede interpretar secuencias de barra invertida) lo que destrozará el binario, no cat. Pero estoy de acuerdo con su punto general.
Comodín

Respuestas:

20

Tienes razón en eso echoy la compañía no parece manejar bien el binario. Sospecho que los caracteres nulos rompen la corriente demasiado pronto.

Puede convertir la información de la imagen en algún formato basado en ASCII. Por ejemplo, esto es con base64:

$ pic=`base64 pic.jpeg`
$ echo $pic | base64 --decode > pic2.jpeg
$ diff pic*
$ echo $?
0
nperson325681
fuente
3
En mi sistema bash tuve que encerrar la variable entre comillas, probablemente porque base64 puede contener espacios en blanco: echo "$pic" | base64 --decode > pic2.jpeg
OldTimer
1

El problema es que los bytes nulos no se pueden pasar a través de argumentos de línea de comandos, ya que se usan internamente como terminadores de argumentos. Todos los demás bytes parecen estar bien. Por lo tanto, una alternativa algo más eficiente (típicamente) al uso base64sería escapar de los bytes nulos y luego usar printfpara convertir los datos a la forma original:

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

Los caracteres \y %son especiales, por printflo que también deben escapar.

También tenga en cuenta que si los datos de entrada terminan con una nueva línea, se eliminarán mediante la sustitución de comandos. Eso no debería ser un problema específico para PNG ya que el último byte en un PNG válido debe ser 0x82, el byte menos significativo en la IENDsuma CRC del fragmento vacío .

Karel Vlk
fuente
1
Si desea aún más barras invertidas, use: sed s/\\\\/\\\\\\\\/g\;s/%/%%/g\;s/\\x00/\\\\x00/g
Karel Vlk