#!/usr/bin/env bash working_dir="$(dirname $(realpath $0))" conf_file="${working_dir}/conf/mysql_credetials.conf" tmp_log_file="$(mktemp)" # ------------- # - Variable settings # ------------- DEFAULT_MYSQL_CREDENTIAL_ARGS="--defaults-file=/usr/local/mysql/sys-maint.cnf" ALL_DATABASES=false DATABASE_NAME_NEEDED=true # ------------- # --- Some functions # ------------- usage() { [[ -n "$1" ]] && error "$1" [[ $terminal ]] && echo -e " \033[1mUsage:\033[m $(basename $0) [DB-Name] \033[1mDescription\033[m Script repairs (and reorganizes) all tables of the given databases by executing MySQL command 'REPAIR TABLE'. If this was successfully, also 'OPTIMIZE TABLE' command will be triggered. If no database was given at command line all tables of ALL databases are checked. \033[1mOptions\033[m No Options available \033[1mFiles\033[m $conf_file: Configuration file " clean_up 1 } clean_up() { # Perform program exit housekeeping rm -f $tmp_log_file exit $1 } echononl(){ if $terminal ; then echo X\\c > /tmp/shprompt$$ if [ `wc -c /tmp/shprompt$$ | awk '{print $1}'` -eq 1 ]; then echo -e -n "$*\\c" 1>&2 else echo -e -n "$*" 1>&2 fi rm /tmp/shprompt$$ fi } fatal(){ echo "" if $terminal ; then if [[ -n "$*" ]] ; then echo -e " [ \033[31m\033[1mFatal\033[m ]: $*" echo "" echo -e " \033[31m\033[1mScript will be interrupted.\033[m\033[m" else echo -e " \033[31m\033[1mFatal error\033[m: \033[1mScript will be interrupted.\033[m" fi else if [[ -n "$*" ]] ; then echo " [ Fatal ]: $*" echo "" echo " Script was terminated.." else echo " Fatal error: Script was terminated.." fi fi echo "" clean_up 1 } error(){ echo "" if $terminal ; then echo -e " [ \033[31m\033[1mError\033[m ]: $*" else echo " [ Error ]: $*" fi echo "" } warn (){ if $terminal ; then echo "" echo -e " [ \033[33m\033[1mWarning\033[m ]: $*" echo "" else echo " [ Warning ]: $*" fi } info (){ if $terminal ; then echo "" echo -e " [ \033[32m\033[1mInfo\033[m ]: $*" echo "" else echo " [ Info ]: $*" fi } echo_ok() { if $terminal ; then echo -e "\033[80G[ \033[32mok\033[m ]" fi } echo_failed(){ if $terminal ; then echo -e "\033[80G[ \033[1;31mfailed\033[m ]" fi } echo_skipped() { if $terminal ; then echo -e "\033[80G[ \033[37mskipped\033[m ]" fi } is_number() { return $(test ! -z "${1##*[!0-9]*}" > /dev/null 2>&1); # - also possible # - #[[ ! -z "${1##*[!0-9]*}" ]] && return 0 || return 1 #return $([[ ! -z "${1##*[!0-9]*}" ]]) } trim() { local var="$*" var="${var#"${var%%[![:space:]]*}"}" # remove leading whitespace characters var="${var%"${var##*[![:space:]]}"}" # remove trailing whitespace characters echo -n "$var" } trap clean_up SIGHUP SIGINT SIGTERM # - Is this script running on terminal ? # - if [[ -t 1 ]] ; then terminal=true else terminal=false fi mysql=`which mysql` if [ -z "$mysql" ]; then if [ -x "/usr/local/mysql/bin/mysql" ]; then mysql=/usr/local/mysql/bin/mysql else fatal "No binary 'mysql' found!" fi fi # - Print help? # - if [[ "$(trim $*)" = "-h" ]] || [[ "$(trim $*)" = "--help" ]] ; then usage fi # ------------- # - Get Database from commandline # ------------- if [[ -n "$1" ]] ; then DATABASE_NAME_NEEDED=false DATABASE_NAME="$1" else DATABASE_NAME="" fi # ------------- # - Load Settings from configuration file # ------------- if $terminal ; then echo "" fi echononl " Loading configuration settings from $(basename ${conf_file}).." if [[ -f "$conf_file" ]]; then source "$conf_file" > $tmp_log_file 2>&1 if [[ $? -eq 0 ]]; then echo_ok else echo_failed fatal "$(cat $tmp_log_file)" fi else echo_skipped if $terminal ;then warn "No Configuration File found. Loading defaults.." fi fi if [[ -n "$mysql_credential_args" ]]; then MYSQL_CREDENTIAL_ARGS="$mysql_credential_args" else MYSQL_CREDENTIAL_ARGS="$DEFAULT_MYSQL_CREDENTIAL_ARGS" fi declare -i index_arr=0 # - Get MySQL Version # - if [[ ${#mysql_credential_args_arr[@]} -gt 0 ]] ; then echo "" echo -e "\033[32m--\033[m" echo "" echo "Which installation contains the database to be repaired?" echo "" echo "" declare -a _tmp_arr=() while [[ $index_arr -lt ${#mysql_credential_args_arr[@]} ]] ; do IFS=':' read -a _val_arr <<< "${mysql_credential_args_arr[$index_arr]}" mysql_version="${_val_arr[0]}" mysql_credential_args="${_val_arr[1]}" mysql_dist_string="$(mysql $mysql_credential_args -N -s -e "SELECT VERSION()" 2> /dev/null)" if [[ "$mysql_dist_string" =~ MariaDB ]]; then mysql_dist="MariaDB $mysql_version" else mysql_dist="MySQL/Percona $mysql_version" fi echo -e " [\033[33m$index_arr\033[m] \033[33m$mysql_dist\033[m" _temp_arr[${index_arr}]="$mysql_credential_args" #_temp_arr+=("$mysql_credential_args") (( index_arr++ )) done _OK=false echo "" echononl "Eingabe: " while ! $_OK ; do read _IN if is_number "$_IN" && [[ -n ${_temp_arr[$_IN]} ]]; then MYSQL_CREDENTIAL_ARGS="${_temp_arr[$_IN]}" _OK=true else echo "" echo -e "\tFalsche Eingabe !" echo "" echononl "Eingabe: " fi done fi if $DATABASE_NAME_NEEDED ; then echo "" echo -e "\033[32m--\033[m" echo "" echo "Insert Database name which should be repaired.." echo "" echo -e " \033[33mLeave empty to repair tables of all databases\033[m" echo "" echononl "Database name: " read DATABASE_NAME #while [ "X$DATABASE_NAME" = "X" ] ; do # echo -e "\n\t\033[33m\033[1mEingabe erforderlich.\033[m\n" # echononl "Database name: " # read DATABASE_NAME #done fi # - Get MySQL Version # - echo "" echo -e "\033[32m--\033[m" echo "" echononl " Get MySQL Version" _version="$(mysql $MYSQL_CREDENTIAL_ARGS -N -s -e "SELECT VERSION()" 2> $tmp_log_file)" if [[ $? -ne 0 ]] ; then echo_failed fatal "$(cat $tmp_log_file)" else echo_ok fi IFS='.' read -r -a version_arr <<< "$_version" declare -i MAJOR_VERSION="${version_arr[0]}" declare -i MINOR_VERSION="${version_arr[1]}" _path_level="${version_arr[2]}" declare -i PATCH_LEVEL="${_path_level%%-*}" ## - Get current MySQL Distribution ## - echononl " Get MySQL distribution .." if [[ -z "$_version" ]]; then echo_failed fatal "No installed MySQL server or distribution found!" elif [[ "$_version" =~ MariaDB ]]; then MYSQL_CUR_DISTRIBUTION="MariaDB" else MYSQL_CUR_DISTRIBUTION="MySQL" fi echo_ok echo "" echo -e "\033[32m--\033[m" echo "" echo "" echo "" echo -e "\033[32m\033[1m====================\033[m" echo "Settings: Repair tables of MySQL Database '$DATABASE_NAME'" echo -e "\033[32m\033[1m====================\033[m" echo "" echo " MySQL Distribution...........: $MYSQL_CUR_DISTRIBUTION" echo " MySQL Version................: ${MAJOR_VERSION}.${MINOR_VERSION}.${PATCH_LEVEL}" echo " MySQL Credentials............: $MYSQL_CREDENTIAL_ARGS" echo "" if [[ -n "$DATABASE_NAME" ]]; then echo " Database name................: $DATABASE_NAME" else echo -e " Database name................: -- \033[033mall databases\033[m --" fi echo "" echo "" echo -e -n "\033[1mContinue repairing tables with above settings? [y/n]:\033[m " read OK while [[ "X${OK}X" = "XX" ]] ; do echo "" echo -e -n "\033[1mContinue with above settings? [y/n]:\033[m " read OK done if [[ "${OK,,}" != 'yes' ]] && [[ "${OK,,}" != 'y' ]]; then fatal "Abort by user request." fi declare -i length_table_name declare -i number_blank_signd declare -i index_i _all_success=true DATABASES="$(mysql $MYSQL_CREDENTIAL_ARGS -N -s -e "show databases")" if [[ -z "$DATABASE_NAME" ]] ; then if $terminal ; then echo "" echo -e " [ \033[37m\033[1m$MYSQL_CUR_DISTRIBUTION ${MAJOR_VERSION}.${MINOR_VERSION}.${PATCH_LEVEL}\033[m ]: repair (and optimize) tables of ALL databases at host '$(hostname -f)'." fi ALL_DATABASES=true else found=false for db in $DATABASES ; do if [[ "$db" = "$DATABASE_NAME" ]]; then DATABASES="$DATABASE_NAME" found=true break fi done if ! $found ; then warn "No Database '$DATABASE_NAME' found at $MYSQL_CUR_DISTRIBUTION ${MAJOR_VERSION}.${MINOR_VERSION}.${PATCH_LEVEL}" clean_up 0 fi fi length_table_name=0 for db in $DATABASES ; do [ "$db" = "information_schema" ] && continue [ "$db" = "performance_schema" ] && continue [ "$db" = "mysql" ] && continue if $terminal ;then echo "" if [[ -n "$DATABASE_NAME" ]] ; then echo -e " [$(date)] Repair (and optimize) tables in database '${db}'.." else echo -e " [ \033[37m\033[1m$MYSQL_CUR_DISTRIBUTION ${MAJOR_VERSION}.${MINOR_VERSION}.${PATCH_LEVEL}\033[m $(date) ] Repair (and optimize) tables in database '${db}'.." fi fi TABLES="$($mysql $MYSQL_CREDENTIAL_ARGS $db -N -s -e "show tables" 2> $tmp_log_file )" if [[ $? -ne 0 ]]; then _all_success=false error "Getting tables of database '${db}' failed.\n $(cat "$tmp_log_file")" error_messages_arr+=("Getting tables of database '${db}' failed.") continue fi for table in $TABLES ; do # - Ommit InnoDB tables # - _engine="$($mysql $MYSQL_CREDENTIAL_ARGS -N -s -e "SELECT ENGINE FROM information_schema.TABLES WHERE TABLE_SCHEMA = '$db' AND TABLE_NAME = '$table'")" if [[ "${_engine,,}" = 'innodb' ]] ; then echo -e " [$(date)] Ommit table '$table' - The storage engine (InnoDB) doesn't support repair" continue fi if $terminal ; then blank_signs="" if [[ $length_table_name -gt ${#table} ]]; then number_blank_sign=$(expr $length_table_name - ${#table}) index_i=0 while [[ $index_i -lt $number_blank_sign ]] ; do blank_signs="$blank_signs " (( index_i++ )) done echo -en "\033[1G" fi echo -en "\033[1G \033[32mRepair table \033[1m$table\033[m$blank_signs\033[1G" fi length_table_name=${#table} $mysql $MYSQL_CREDENTIAL_ARGS $db -N -s -e "REPAIR TABLE \`$table\`" > $tmp_log_file 2>&1 if [[ $? -ne 0 ]]; then _all_success=false error "Repairing table '$table' failed.\n$(cat "$tmp_log_file")" error_messages_arr+=("$MYSQL_CUR_DISTRIBUTION ${MAJOR_VERSION}.${MINOR_VERSION}.${PATCH_LEVEL}: Error while repairing table '${table}' of database '$db'.") else $mysql $MYSQL_CREDENTIAL_ARGS $db -N -s -e "OPTIMIZE TABLE \`$table\`" > $tmp_log_file 2>&1 if [[ $? -ne 0 ]]; then error "Reoptimizing table \"${table}\" of database \"$db\" failed.\n$(cat "$tmp_log_file")" error_messages_arr+=("$MYSQL_CUR_DISTRIBUTION ${MAJOR_VERSION}.${MINOR_VERSION}.${PATCH_LEVEL}: Error while (re-)optimizing table '${table}' of database '$db'.") fi fi done if $terminal ;then echo -en "\033[1G [$(date)] End repairing tables of database '${db}'.." echo fi done if $_all_success ; then if $ALL_DATABASES ; then info_messages_arr+=("$MYSQL_CUR_DISTRIBUTION ${MAJOR_VERSION}.${MINOR_VERSION}.${PATCH_LEVEL}: Repairing MySQL tables of all databases was successful.") else info_messages_arr+=("$MYSQL_CUR_DISTRIBUTION ${MAJOR_VERSION}.${MINOR_VERSION}.${PATCH_LEVEL}: Repairing MySQL tables of database '${db}' was successful.") fi fi if $terminal && $ALL_DATABASES ; then echo "" echo -e " [ \033[37m\033[1m$MYSQL_CUR_DISTRIBUTION ${MAJOR_VERSION}.${MINOR_VERSION}.${PATCH_LEVEL}\033[m ]: Finished repairing MySQL databases at host $(hostname -f)." echo "" fi if [[ ${#info_messages_arr[@]} -gt 0 ]]; then for msg in "${info_messages_arr[@]}" ; do if $terminal ; then info "$msg" fi done fi if [[ ${#error_messages_arr[@]} -gt 0 ]]; then for msg in "${error_messages_arr[@]}" ; do if $terminal ; then error "$msg" fi done fi clean_up 0