===== Правим до идеала, спрашиваем все, что непонятно=====
Все неверные решения добавляем в комменты и потом уже правим\\
#!/bin/bash
echo "$0 $@ [$$] START" >&2
set -euE
if [ "${1:---help}" = "--help" ]; then
echo 'Info: Создает бекап mysql бд и отправляет его в git origin, таблицы пофайлово'
echo "Usage: $0 --user=root --password=mypass --host=localhost DB_NAME BACKUP_DIR"
echo 'Example: restore: git log; git checkout;'
echo 'Example: restore: for f in *.sql.*; do cat $f >>new.sql; done;'
echo 'Example: restore: /usr/bin/mysql -uroot -p123 < new.sql'
exit 0
fi
ARG_USER="${1/--user=/}"
ARG_PASSWORD="${2/--password=/}"
ARG_DB_HOST="${3/--host=/}"
ARG_DB_NAME="${4}"
ARG_BACKUP_DIR="${5}"
PREFIX="${ARG_DB_NAME}.sql"
prepare(){
if [ ! -d .git ]; then
git init .
echo '*.sql' > .gitignore
git add .gitignore
git commit -m init
fi
if git remote show origin; then
git pull origin master
fi
return 0
}
mysqldump_csplit_per_table(){
set -o pipefail
mysqldump --user="$ARG_USER" --host="$ARG_DB_HOST" --password="$ARG_PASSWORD" \
--opt -c --databases "$ARG_DB_NAME" \
--skip-quick \
--add-drop-table --add-drop-database --skip-extended-insert \
--create-options --single-transaction \
| csplit -n 4 -s -f"$PREFIX.table." - '/-- Table structure for table/' '{*}'
set +o pipefail
return 0
}
table_split_per_size10MB(){
local table=""
for table in "$PREFIX.table."*; do
if [ $(stat -c %s "$table") -gt $((10*1024*1024)) ]; then
split -a 4 -d -b 10M "$table" "$table.split."
rm -f "$table";
fi
done
return 0
}
git_commit_push(){
local ret
git add .
ret=$( git status )
if [[ "$ret" != *'nothing to commit'* ]]; then
git commit -am $(date +%Y-%m-%d_%H-%M)
fi
git gc
if git remote show origin; then
git push origin master
fi
return 0
}
main(){
cd "$ARG_BACKUP_DIR"
rm -f "$PREFIX.table."*
mysqldump_csplit_per_table
table_split_per_size10MB
git_commit_push
return 0
}
main
echo "$0 $@ [$$] SUCCESS" >&2
exit 0
===== Разбор скрипта =====
#!/bin/bash
### Весь bash скрипт рассматриваем как инстанс объекта crab_mysqldump2git
### Глобальные переменные - это атрибуты(property) объекта
### функции - это методы объекта, либо иногда, это аналоги команд OS.
### если функция работает с переменной, которая не является атрибутом объекта,
### то она должна быть с входными параметрами
echo "$0 $@ [$$] START" >&2
### падаем при любых необработанных ошибках
set -euE
### Делаем --help самом верху скрипта тк он же является и инфо о скрипте и сразу понятно, что делает скрипт
if [ "${1:---help}" = "--help" ]; then
echo 'Info: Создает бекап mysql бд и отправляет его в git origin, таблицы пофайлово'
echo "Usage: $0 --user=root --password=mypass --host=localhost DB_NAME BACKUP_DIR"
echo 'Example: restore: git log; git checkout;'
echo 'Example: restore: for f in *.sql.*; do cat $f >>new.sql; done;'
echo 'Example: restore: /usr/bin/mysql -uroot -p123 < new.sql'
exit 0
fi
### Подготовительная работа
### Подготавливаем глобальные переменные, что тождественно приватным property объекта self
### по сути понимаем, что $ARG_USER - это self.user или crab_mysqldump2git.user
### все аргументы записываем в ARG_NAME=значение, если это опция ARG_OPTNAME=TRUE, если позиционная в массив ARGV[$ARGC]="$i"
### стараемся глобальные переменные устанавливать в начале скрипта так удобней для чтения
# self.ARG_USER="${1/--user=/}"
ARG_USER="${1/--user=/}"
# self.ARG_PASSWORD="${2/--password=/}" и т.д.
ARG_PASSWORD="${2/--password=/}"
ARG_DB_HOST="${3/--host=/}"
ARG_DB_NAME="${4}"
ARG_BACKUP_DIR="${5}"
PREFIX="${ARG_DB_NAME}.sql"
### подготовительная работа действия, инициализация каталога при необходимости и тп
prepare(){
### Присвоение глобальных переменных и ARG_NAME здесь не делаем, делаем в начале скрипта
if [ ! -d .git ]; then
git init .
echo '*.sql' > .gitignore
git add .gitignore
git commit -m init
fi
if git remote show origin; then
git pull origin master
fi
return 0
}
### Что такое объектный подход в stronbash
### Описание пользовательских команд(методов) и функций
### метод может работать с глобальными переменным без входящих значений
### если эти переменные это атрибут объекта self-script или его ARG_NAME CONF_NAME переменные
### но если это иные переменные, то обязательно делать через входные значения
### например ТОЛЬКО аргументом если мы обрабатываем файлы циклом,
### через for file in /tmp/mysql/*; do funct_name "$file"; done
# self.mysqldump_csplit_per_table()
mysqldump_csplit_per_table(){
set -o pipefail
mysqldump --user="$ARG_USER" --host="$ARG_DB_HOST" --password="$ARG_PASSWORD" \
--opt -c --databases "$ARG_DB_NAME" \
--skip-quick \
--add-drop-table --add-drop-database --skip-extended-insert \
--create-options --single-transaction \
| csplit -n 4 -s -f"$PREFIX.table." - '/-- Table structure for table/' '{*}'
set +o pipefail
return 0
}
# self.table_split_per_size10MB()
table_split_per_size10MB(){
local table=""
for table in "$PREFIX.table."*; do
if [ $(stat -c %s "$table") -gt $((10*1024*1024)) ]; then
split -a 4 -d -b 10M "$table" "$table.split."
rm -f "$table";
fi
done
### return 0 всегда обязательно, иначе вызов функции может упасть тк вернется не ноль после цикла или if,
### а код возврата от последней команды даже если мы его обработали и он не приведет к локальному падению
return 0
}
git_commit_push(){
local ret
git add .
ret=$( git status )
if [[ "$ret" != *'nothing to commit'* ]]; then
git commit -am $(date +%Y-%m-%d_%H-%M)
fi
git gc
if git remote show origin; then
git push origin master
fi
return 0
}
### основной алгоритм скрипта, это последовательность команд и методов
### простейшие команды не выносим в отдельные методы
main(){
### КОМАНДА №1
cd "$ARG_BACKUP_DIR"
### КОМАНДА №2
rm -f "$PREFIX.table."*
### КОМАНДА №3 - это Команда-Метод объекта self-script, он использует глобальные переменные, которые по сути атрибуты объекта self-script и это нормально, что мы не передаем параметры
mysqldump_csplit_per_table
### КОМАНДА №4 - это Команда-Метод
table_split_per_size10MB
### КОМАНДА №5 - это Команда-Метод
git_commit_push
return 0
}
main
echo "$0 $@ [$$] SUCCESS" >&2
### exit 0 обязателен потому что, если в конце будет условие или выход из цикла и забудешь написать exit 0, то вернется не ноль и все упадет. Всегда надо делать exit 0 и return 0 и не думать каждый раз - это позволит избежать кучу проблем и освобождает мозг.
### Если нужно вернуть не 0 делаем явно [ $ret != 0 ] && exit $ret
exit 0
{(rater>id=1|name=правила_разработки:как_надо_делать:разбор_crab_mysqldump2git|type=vote|trace=user|tracedetails=1)}
~~OWNERAPPROVE~~