Как сохранить файл изображения в переменной bash?

14

После того, как я использую следующую команду,

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

Я не могу открыть tmp.png как файл PNG. Может быть, некоторая информация теряется, когда я использую $pngStringдля хранения файла изображения.

Итак, вопрос: как я могу сохранить полную информацию об изображении, используя переменную в скрипте bash?

Либин Вэнь
источник
Команда cat работает отлично (для сохранения данных изображения в переменной). Просто удалите двойные кавычки. Вопрос в том, что вы хотите сделать с этими данными после сохранения их в переменной?
coffeMug
5
catи echoвсе это в душе текстовые утилиты. Если они будут ничего не подозревать о двоичных файлах, это приведет к непредсказуемым результатам. Вот почему такие вещи base64были изобретены.
Шадур
Почему вы хотите иметь его в качестве переменной? Переменные оболочки обычно предназначены для хранения небольшого объема текста, а не больших объемов двоичных данных. Ни одна из обычных оболочек не может справиться с двоичными данными в переменных (они подавляются нулевыми байтами), кроме zsh.
Жиль "ТАК - перестань быть злым"
Почему бы просто cat example.png > tmp.pngили еще лучше cp example.png tmp.png?
Wildcard
@Shadur, на catсамом деле не текстовая утилита. Это подстановка команды (которая удаляет завершающие символы новой строки), присваивание переменной (которая не может содержать нулевые байты) и echoкоманда (которая может интерпретировать последовательности с обратной косой чертой), которая будет искажать двоичный файл, а не cat. Но я согласен с вашей общей точкой зрения.
Wildcard

Ответы:

20

Вы правы в этом, echoи компания, кажется, плохо справляется с бинарным. Я подозреваю, что нулевые символы прерывают поток слишком рано.

Вы можете преобразовать информацию об изображении в некоторый формат на основе ASCII. Например, это с base64:

$ pic=`base64 pic.jpeg`
$ echo $pic | base64 --decode > pic2.jpeg
$ diff pic*
$ echo $?
0
nperson325681
источник
3
В моей системе bash я должен был заключить переменную в кавычки, возможно потому, что base64 может содержать пробелы: echo "$pic" | base64 --decode > pic2.jpeg
OldTimer
1

Проблема в том, что нулевые байты не могут быть переданы через аргументы командной строки, поскольку они используются внутри в качестве ограничителей аргументов. Все остальные байты вроде бы в порядке. Таким образом, несколько более экономичной (обычно) альтернативой использованию base64будет экранирование нулевых байтов, а затем использование printfдля преобразования данных в исходную форму:

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

\И %символы имеют специальное значение, printfпоэтому они должны быть экранированы тоже.

Также обратите внимание, что если входные данные заканчиваются символом новой строки, они будут удалены путем подстановки команд. Это не должно быть проблемой конкретно для PNG, так как последний байт в допустимом PNG должен быть 0x82, наименее значимый байт в IENDсумме CRC пустого фрагмента.

Карел Влк
источник
1
Если вы хотите еще больше обратной косой черты, используйте: sed s/\\\\/\\\\\\\\/g\;s/%/%%/g\;s/\\x00/\\\\x00/g
Karel Vlk