Comment stocker un fichier image dans une variable bash?

14

Après avoir utilisé la commande suivante,

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

Je ne peux pas ouvrir le tmp.png en tant que fichier PNG. Peut-être que certaines informations sont perdues lorsque j'utilise $pngStringpour stocker le fichier image.

La question est donc: comment puis-je stocker les informations d'image complètes en utilisant une variable dans le script bash?

Libin Wen
la source
La commande cat fonctionne correctement (pour stocker les données d'image dans la variable). Supprimez simplement les guillemets doubles. La question est de savoir ce que vous voulez faire de ces données après les avoir enregistrées dans la variable?
coffeMug
5
catet echoet tous ses semblables sont au cœur des utilitaires de texte . Les laisser se perdre sans méfiance sur les fichiers binaires aura des résultats imprévisibles. C'est pourquoi des choses comme base64ont été inventées.
Shadur
Pourquoi voulez-vous l'avoir comme variable? Les variables shell sont généralement destinées à stocker une petite quantité de texte, pas de grandes quantités de données binaires. Aucun des shell habituels ne peut faire face aux données binaires dans les variables (ils s'étouffent sur des octets nuls) sauf zsh.
Gilles 'SO- arrête d'être méchant'
Pourquoi pas juste cat example.png > tmp.pngou mieux encore cp example.png tmp.png?
Wildcard
@Shadur, catn'est pas vraiment un utilitaire de texte. C'est la substitution de commande (qui supprime les sauts de ligne de fin), l'affectation de variable (qui ne peut pas contenir d'octets nuls) et la echocommande (qui peut interpréter les séquences de barre oblique inverse) qui gèreront le binaire, non cat. Mais je suis d'accord avec votre point global.
Wildcard

Réponses:

20

Vous avez raison echoet la société ne semble pas bien gérer le binaire. Je soupçonne que les caractères nuls interrompent le flux trop tôt.

Vous pouvez convertir les informations d'image dans un format basé sur ASCII. Par exemple, c'est avec base64:

$ pic=`base64 pic.jpeg`
$ echo $pic | base64 --decode > pic2.jpeg
$ diff pic*
$ echo $?
0
nperson325681
la source
3
Dans mon système bash, j'ai dû mettre la variable entre guillemets, probablement parce que base64 peut contenir des espaces blancs: echo "$pic" | base64 --decode > pic2.jpeg
OldTimer
1

Le problème est que les octets nuls ne peuvent pas être passés via les arguments de ligne de commande car ils sont utilisés en interne comme terminateurs d'argument. Tous les autres octets semblent corrects. Ainsi, une alternative un peu plus économe en espace (généralement) à l'utilisation base64serait d'échapper les octets nuls, puis d'utiliser printfpour convertir les données au format d'origine:

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

Les caractères \et %sont spécifiques à printfdonc ils doivent également être échappés.

Notez également que si les données d'entrée se terminent par une nouvelle ligne, elles seront supprimées par substitution de commande. Cela ne devrait pas être un problème spécifique pour les PNG car le dernier octet dans un PNG valide doit être 0x82, l'octet le moins significatif dans la IENDsomme CRC du bloc vide .

Karel Vlk
la source
1
Si vous voulez encore plus de contre-obliques, utilisez: sed s/\\\\/\\\\\\\\/g\;s/%/%%/g\;s/\\x00/\\\\x00/g
Karel Vlk