===== Правим до идеала, спрашиваем все, что непонятно===== Все неверные решения добавляем в комменты и потом уже правим\\ #!/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~~