самораспаковывающийся tar-архив (скрипты оболочки)

Я попытался написать сценарий оболочки, который создает еще один самораспаковывающийся tar-архив, заархивированный и закодированный в base64. Я не знаю, куда идти, и у меня практически нет опыта написания сценариев оболочки.

Так как этот скрипт создает tar-архив, который заархивирован и закодирован, но самораспаковка не работает, когда я пытаюсь запустить ./tarName из терминала. Любой совет приветствуется

#!/bin/sh
tarName=$1;

if [ -e $tarName.tar.gz ] 

    then /bin/echo "$tarName already exists" 
    exit 0
fi

shift;
for files;
do
    tar -czvf tmpTarBall.tar.gz $files;
done

echo "#!/bin/sh" >> $tarName.tar.gz;
echo "base64 -d $tarName.tar.gz"  >> $tarName.tar.gz;
echo "tar -xzvf $tarName.tar.gz" >> $tarName.tar.gz;
chmod +x ./$tarName.tar.gz;

base64 tmpTarBall.tar.gz >> $tarName.tar.gz;
rm tmpTarBall.tar.gz;

----------ОБНОВИТЬ

Немного осмотрелся, и это то, что у меня есть сейчас, все еще не работает. Может ли кто-нибудь объяснить мне, почему?

#!/bin/sh
tarName=$1;

if [ -e $tarName.tar.gz ] 

    then /bin/echo "$tarName already exists" 
    exit 0
fi

shift;
for files;
do
    tar -czvf tmpTarBall.tar.gz $files;
done

cat > extract.sh;
echo "#!/bin/sh" >> extract.sh;
echo "sed '0,/^#TARBALL#$/d' $0 | $tarName.tar.gz | base64 -d | tar -xzv; exit 0" >> extract.sh;
echo "#TARBALL#" >> extract.sh;

cat extract.sh tmpTarBall.tar.gz > $tarName.tar.gz;
chmod +x ./$tarName.tar.gz;

rm extract.sh tmpTarBall.tar.gz;

Когда я пытаюсь запустить tarName.tar.gz, я получаю ошибки: ./tarName.tar.gz: 2: ./tarName.tar.gz: tarName.tar.gz: not found gzip: stdin: неожиданный конец файла tar : дочерний элемент вернул статус 1 tar: ошибка неустранима: выход сейчас


person minusila    schedule 10.03.2016    source источник
comment
exit 1 когда что-то идет не так — exit 0 указывает на успех. Вы должны заменить цикл for только на tar -czvf tmpTarBall.tar.gz "$@", чтобы поместить все файлы в архив. Опция c каждый раз создает файл tar; поэтому вы сохранили только последний файл в списке.   -  person Jonathan Leffler    schedule 10.03.2016
comment
Вам нужно тщательно продумать, как должен выглядеть сгенерированный сценарий оболочки, потому что это определит, что ваш сценарий оболочки должен сделать для его создания. Ваша текущая предложенная командная строка сомнительна по многим причинам, не в последнюю очередь потому, что вы не можете передать данные через сжатый tar-файл в обычном ходе событий. В целом вам, вероятно, следует использовать параметр -b num для установки длины строки в закодированном выводе из base64 (это правильно для Mac OS X; есть шанс, что версия GNU использует другой параметр).   -  person Jonathan Leffler    schedule 11.03.2016


Ответы (2)


Обязательно ли делать это самостоятельно? Существует инструмент под названием makeself, который может сделать это за вас. Если вам нужно написать это самостоятельно, вот несколько соображений:

Ваш выходной файл представляет собой архив с прикрепленным к нему сценарием оболочки. Процесс извлечения запускает весь выходной файл через base64 и tar, а не только архив. Вызов base64 превращает часть скрипта в мусор, который затем сбивает с толку tar. Что вам нужно сделать, так это добавить некоторый код, который будет отделять сценарий от архива, а затем запускать оставшиеся команды только для части архива. Один из возможных способов сделать это — изменить скрипт извлечения примерно так:

#!/bin/sh
linenum=$(grep -n "__END_OF_SCRIPT_MARKER__" $tarName.tar.gz | tail -1 | sed -e 's/:.*//')
tail -n +$(($linenum + 1)) $tarName.tar.gz | base64 -d | tar -xzv
exit 0
__END_OF_SCRIPT_MARKER__

Убедитесь, что в части сценария, следующей за текстом маркера, нет ничего, кроме символа новой строки (который не виден разметкой на этом веб-сайте). При этом вы используете grep, чтобы найти номер строки, содержащей маркер, а затем удаляете столько строк с помощью tail. То, что останется, будет архивной частью, которая обычно обрабатывается остальной частью вашего кода. Строка exit гарантирует, что оболочка не попытается выполнить текст маркера или содержимое архива как код. Вы можете сохранить код извлечения в менее сжатом формате, если хотите, но в конечном итоге вам придется создать временный файл для части архива и убедиться, что он будет удален.

person bta    schedule 10.03.2016
comment
Когда я пытаюсь повторить это в своем файле, не все включается. я получаю: #!/bin/sh linenum= tail -n +1 newTarTest.tar.gz | base64 -d | tar -xzv exit 0 __END_OF_SCRIPT_MARKER__ - person minusila; 11.03.2016
comment
@minusila - при использовании эха для записи скрипта в выходной файл вам нужно экранировать специальные символы, такие как $(). В противном случае оболочка оценит их до того, как произойдет эхо. - person bta; 20.03.2016

Желаемый результат

В общих чертах сценарий, который вы хотите сгенерировать, должен выглядеть так:

base64 -d <<'EOF' | tar -xzf -
…base-64 encoded data…
EOF

Команда base64 декодирует свой стандартный ввод, который представлен здесь как документ, заканчивающийся строкой, содержащей только EOF. Вывод записывается в tar с возможностью извлечения сжатых данных, считанных из стандартного ввода.

Минимальный скрипт

Итак, минимальный скрипт генератора выглядит так:

echo "base64 -d <<'EOF' | tar -czf -"
tar -czf - "$@" | base64 -w 72
echo "EOF"

Это повторяет строку base64 … | tar …, затем использует tar для создания на стандартном выходе заархивированного tar-файла, содержащего файлы или каталоги, указанные в командной строке, и вывод передается в версию base64 GNU coreutils с возможностью указать, что выходные строки должны иметь ширину 72 символа (плюс новая строка). За всем этим следует EOF, чтобы отметить конец документа здесь.

Вы можете добавить строки shebang (#!/bin/sh) в один или оба скрипта. Нет необходимости выбирать более конкретную оболочку; при этом используются только базовые конструкции сценариев оболочки, которые работали еще в былые времена — до того, как POSIX был блеском в чьих-то глазах.

Возможные осложнения

Возможные осложнения включают поддержку Mac OS X base64, которая имеет такое сообщение об использовании:

Usage:  base64 [-dhvD] [-b num] [-i in_file] [-o out_file]
  -h, --help     display this message
  -D, --decode   decodes input
  -b, --break    break encoded string into num character lines
  -i, --input    input file (default: "-" for stdin)
  -o, --output   output file (default: "-" for stdout)

Параметр -v и параметр -d генерируют base64: invalid option -- v (для соответствующей буквы) плюс использование. Кажется, нет способа получить от него информацию о версии. Однако base64 GNU генерирует полезное сообщение, когда вы запрашиваете base64 --version. Первая строка стандартного вывода будет содержать что-то вроде:

base64 (GNU coreutils) 8.22
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Written by Simon Josefsson.

Это записывается в стандартный вывод. Таким образом, вы можете автоматически определить, есть ли у вас GNU base64, и соответствующим образом адаптироваться. Вам понадобится один тест в скрипте генератора и копия теста в сгенерированном скрипте. Это определенно более совершенная программа.

person Jonathan Leffler    schedule 11.03.2016