КАК Я ПЕРЕСТАЛ БОЯТЬСЯ И ПОЛЮБИЛ BASH
дамп / восстановление / миграция web-сервера
Я уже выкладывал образцы простеньких bash-скриптов, например, для сборки cubic проектов или программы автозапуска, но здесь будет немного более сложная задачка, а именно создание дампа и восстановление рабочего веб-сервера Apache. Суть сводится к тому, чтобы писать как можно меньше букав и не компостировать себе мозги в таком случае, например, если сервер упадет и не очнется. Проект будет состоять из двух этапов. На первом мы запускаем скрипт dump.sh, он проверяет, какие есть настройки, папки, базы и т. д., затем все это дело копирует в некий специально-заготовленный каталог и тут же автоматически создает другой скрипт, deploy.sh. На втором этапе deploy.sh установит apache, mysql и восстановит всю прежнюю конфигурацию, не задавая попутно идиотских вопросов. Полагаю, это может понадобиться не только на аварийный случай, когда система поломается в результате каких-то неудачных экспериментов, но так же при миграции, скажем, на другое железо.
ЭТАП 1-Й ДАМП
Ох, намучился, пока разбирался, за то победил! Победил с первой половиной. Чтобы не писать самому, естественно, решил сначала нагуглить готовое решение. Нашелся интересный вариант на этом сайте.
nano dump.sh
#!/usr/local/bin/bash # MySQL backup script #ulimit -t 3600 #user name USER="madmentat" #user password PASSWORD="Password666" #MYSQL host address ("localhost" by default) HOST="localhost" #dirrectory for backups DIR="/data/fileserver/share/mysqldump" GZIP="$(which gzip)" MYSQL="$(which mysql)" MYSQLDUMP="$(which mysqldump)" NOW=$(date +"%Y_%m_%d_%H-%M") echo "Choose database number:" i=1 for db in $($MYSQL -u$USER -h$HOST -p$PASSWORD -Bse 'show databases') do echo "$i - $db" DATABASES[$i]=$db i=$((i+1)) done read RESULT if [ "$RESULT" -ge 1 ] && [ "$RESULT" -lt ${#DATABASES[@]} ] then eval "DB=${DATABASES[$RESULT]}" eval "FILE=$DIR$DB-$NOW.sql.gz" $MYSQLDUMP -u$USER -h$HOST -p$PASSWORD $DB | $GZIP -9 > $FILE else echo "Wrong number!" fi
Однако, скрипт не заработал, ругался нехорошими словами на строку 23.
mysqldump.sh: 23: DATABASES[1]=base: not found
По аналогии с C++, я сразу понял что там какой-то массив и всякое вот это, и вроде бы все сходится, но что значит "not found"?! Пытался распросить народ на /ru.stackoverflow.com/, там никто толком не помог. Пришлось разбираться самому. В итоге нашел похожий кейс на английском stackoverflow и там мужик в конце объяснил одну прикольную штуку, дескать, bash-скрипты следует запускать не sh командой, типа
sh dump.sh
а через точку, т. е., так:
./dump.sh
Я не очень силен в разных языках, тем более в английском... "Alice in wonderland" осилил, а вот "Brave new world" не смог, как и "Orange Clockwork"... Поэтому хз чего он там балакал. Дословно следующее:
This can happen if you override the intended interpreter. E.g this will run with sh regardless of what hash bang is used (handy when not using hash bang): > sh run.sh OR to run bash: > bash run.sh To let it use the script defined hash bang value, use this: > ./run.sh
Еще один крендель написал об этом по-русски:
"На счет запуска, правильно и так и так, просто если в первом случае вы явно указываете обработчик, то во втором случае используется обработчик прописаный в шебанге. Кроме того, если в первом случае скрипт будет выполнен в любом случае, то во втором только если пользователь обладает правом на запуск этого файла. И да, в вашем первом варианте вы пытаетесь запустит bash (как я понимаю) скрипт в sh"
Сразу ясно: оба сказали что-то очень умное и по делу. Но что я из этого извлек? За меня ответит Сергей Демихов:
Похоже, bash и sh - не совсем одно и то же. В общем, доперев, как работать с массивами, я убедился, что изначальный вариант все равно не... не... Как бы это сказать-то, чтобы без мата? Ну, вот конструкции "if - then - fi" логически еще как-то можно осознать, но... Эти "read, eval" и всякое такое - по-моему, какая-то хрень. Вообще, при том что у меня реально мало опыта программирования, я уже понимаю одну вещь: чем более простой и тупой твой код, тем лучше - во всяком случае, так меньше вероятности что ты там навертишь чего-нибудь не того. "eval", в теории, можно понять, но к чему тут "read" - решил уже даже не разбираться - ну нахрен. Точнее, подумал что, в принципе, не понимаю зачем нужен оператор read в bash, а уж тем более в данном примере, и решил все упростить, запихав необходимые операции в цикл "for":
#!/bin/bash # MySQL backup script, writen by genious supermind-programmer madmentat #ulimit -t 3600 #user name USER="madmentat" #user password PASSWORD="Password666" #MYSQL host address ("localhost" by default) HOST="localhost" #dirrectory for backups mkdir -p /data/fileserver/dump/mysql mkdir -p /data/fileserver/dump/etc SQLDUMPDIR="/data/fileserver/dump/mysql" DUMPDIR="/data/fileserver/dump" GZIP="$(which gzip)" MYSQL="$(which mysql)" MYSQLDUMP="$(which mysqldump)" NOW=$(date +"%Y_%m_%d_%H-%M") echo "Choose database number:" i=1 for db in $($MYSQL -u$USER -h$HOST -p$PASSWORD -Bse 'show databases') do DATABASES[$i]=$db FILE[$i]=$SQLDUMPDIR/${DATABASES[$i]}-$NOW.sql echo "${FILE[$i]}" mysqldump -u$USER -h$HOST -p$PASSWORD ${DATABASES[$i]} > ${FILE[$i]} i=$((i+1)) done echo "MySQL dumps are done! Look for your files in $MYSQLDIR" cp -r /etc/php $DUMPDIR/etc/php cp -r /etc/apache2 $DUMPDIR/etc/apache2
echo "Apache server files are saved in $DUMPDIR"
И вот этот вариант уже реально выкладывает дампы sql в директорию, прописанную в $DIR!
ЭТАП 2-Й ВОССТАНОВЛЕНИЕ
Здесь сложность упирается в то, чтобы установить LAMP без идиотских вопросов. Отмечу, что идиотскими у нас считаются любые вопросы, скрипт должен работать тихо.
Продолжение следует...