Bagaimana cara menyimpan file gambar dalam variabel bash?

14

Setelah saya menggunakan perintah berikut,

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

Saya tidak bisa membuka tmp.png sebagai file PNG. Mungkin beberapa informasi hilang ketika saya gunakan $pngStringuntuk menyimpan file gambar.

Jadi pertanyaannya adalah: Bagaimana saya bisa menyimpan informasi gambar lengkap menggunakan variabel dalam skrip bash?

Libin Wen
sumber
Perintah cat berfungsi dengan baik (untuk menyimpan data gambar dalam variabel). Hapus saja tanda kutip ganda. Pertanyaannya adalah apa yang ingin Anda lakukan dengan data ini setelah menyimpannya dalam variabel?
coffeMug
5
catdan echodan semua sejenisnya adalah utilitas teks hati . Membiarkannya lepas tanpa curiga pada file biner akan memiliki hasil yang tidak terduga. Itu sebabnya hal-hal seperti base64diciptakan.
Shadur
Mengapa Anda ingin memilikinya sebagai variabel? Variabel Shell biasanya dimaksudkan untuk menyimpan sejumlah kecil teks, bukan sejumlah besar data biner. Tak satu pun dari shell yang biasa dapat mengatasi data biner dalam variabel (mereka tersedak byte nol) kecuali zsh.
Gilles 'SANGAT berhenti menjadi jahat'
Kenapa belum cat example.png > tmp.pngatau lebih baik cp example.png tmp.png,?
Wildcard
@ Safur, catsebenarnya bukan utilitas teks. Ini adalah substitusi perintah (yang menghapus baris baru), penugasan variabel (yang tidak dapat berisi byte nol) dan echoperintah (yang dapat menginterpretasikan urutan backslash) yang akan memotong-motong biner, bukan cat. Tapi saya setuju dengan poin keseluruhan Anda.
Wildcard

Jawaban:

20

Anda benar dalam hal itu echo& perusahaan sepertinya tidak menangani biner dengan baik. Saya menduga bahwa karakter nol memecah aliran terlalu dini.

Anda dapat mengonversi informasi gambar dalam beberapa format berbasis ASCII. Misalnya, ini dengan base64:

$ pic=`base64 pic.jpeg`
$ echo $pic | base64 --decode > pic2.jpeg
$ diff pic*
$ echo $?
0
nperson325681
sumber
3
Dalam sistem bash saya, saya harus menyertakan variabel dalam tanda kutip, mungkin karena base64 dapat berisi ruang putih: echo "$pic" | base64 --decode > pic2.jpeg
OldTimer
1

Masalahnya adalah bahwa byte nol tidak dapat melewati argumen baris perintah karena mereka digunakan secara internal sebagai terminator argumen. Semua byte lain tampaknya baik-baik saja. Jadi alternatif yang agak lebih hemat-ruang (biasanya) untuk menggunakan base64adalah untuk menghindari byte nol dan kemudian menggunakan printfuntuk mengkonversi data ke bentuk asli:

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

The \dan %karakter khusus untuk printfsehingga mereka harus melarikan diri juga.

Juga perhatikan bahwa jika data input diakhiri dengan baris baru, itu akan dilucuti oleh substitusi perintah. Itu seharusnya tidak menjadi masalah khusus untuk PNG karena byte terakhir dalam PNG yang valid harus 0x82, byte paling signifikan dalam IENDjumlah CRC potongan kosong .

Karel Vlk
sumber
1
Jika Anda ingin lebih banyak backslash, gunakan: sed s/\\\\/\\\\\\\\/g\;s/%/%%/g\;s/\\x00/\\\\x00/g
Karel Vlk