Приемы написания скриптов на Bash. #2

Это пример для статьи: Приемы написания скриптов в Bash #2


Оглавление

Скрипт клонирования (синхронизации) директорий

#!/bin/bash
curScript="$0"
a1=./myfunc ; source "$a1" ; if [ $? -ne 0 ] ; then echo "Ошибка — нет библиотеки функций $a1" 1>&2 ; exit 1 ; fi

#set -x

rsync="/usr/bin/rsync" # Полный путь к команде rsync
nohup="/usr/bin/nohup" # Полный путь к команде nohup

# Объявление переменных
fixPrmCnt=0   # Счетчик фиксированных параметров
pInter=       # Интерактивный режим
pLogFile=/var/log/dir-sync.log # Имя лог-файла
pUpdate=      # Режим обновления
pShowCmd=     # Показать команду rsync
pDryRun=      # Холостой режим
pBackgr=      # Выполнять в фоне
pSrcDir=      # Директория источник
pDstDir=      # Директория приемник

RSCmd=        # Команда rsync
RSPrm=        # Дополнительные параметры rsync

# --- Создание команды rsync ---
createCmd()
{
        local n

        RSCmd="$rsync"

        if [ "$pUpdate" = "1" ] ; then
                RSCmd="$RSCmd -urlptgoDvEAH"
        else
                RSCmd="$RSCmd -rlptgoDvEAH --delete"
        fi

        # Если в фоне - не надо никакого вывода, и наоборот
        if [ "$pBackgr" = "1" ] ; then
                RSCmd="$RSCmd -q"
        else
                RSCmd="$RSCmd --progress -v"
        fi

        if [ "$pDryRun" = "1" ] ; then
                RSCmd="$RSCmd -n"
        fi

        RSCmd="$RSCmd --super --force"

        # Дополнительные параметры - элементами массива
        n=-1
        ((n++)) ; RSPrm[n]="--log-file=$pLogFile"
        ((n++)) ; RSPrm[n]="$pSrcDir/"
        ((n++)) ; RSPrm[n]="$pDstDir/"
}

usage()
{
        echo "Скрипт ${curScript##*/}"
        echo "Использование: ${curScript##*/} [ключи] <дир-источник> <дир-приемник>"
        cat <<'EOF'
Ключи:
 -i , --interactive     интерактивный режим
 -n,  --dry-run         холостое исполнение (только сообщения)
 -lf, --log-file        задает имя лог-файла (умолчание: /var/log/dir-sync.log)
 -u,  --update          режим обновления
 -sc, --show-command    показать команду rsync
 -bg, --background      выполнять в фоне (nohup)
EOF
}


showInfo()
{
        local a1

        if [ "$pUpdate" = "1" ] ; then
                a1="обновление"
        else
                a1="клонирование"
        fi

        padMid 80 "Режим" "$a1" ; echo $cRes
        padMid 80 "Источник" "$pSrcDir" ; echo $cRes
        padMid 80 "Приемник" "$pDstDir" ; echo $cRes
        padMid 80 "Лог-файл" "$pLogFile" ; echo $cRes

        transYesNoRu $pBackgr
        padMid 80 "Выполнять в фоне" "$cRes" ; echo $cRes

        transYesNoRu $pDryRun
        padMid 80 "Выполнять в холостом режиме" "$cRes" ; echo $cRes
}

if [ -z "$1" ] ; then
        usage
        exit
fi

while [ 1 ] ; do
   if [ "$1" = "--yes" ] ; then
      pYes=1
   elif [ "$1" = "-i" ] ; then
                pInter=1
   elif [ "$1" = "--interactive" ] ; then
                pInter=1
   elif procParmS "-lf" "$1" "$2" ; then
                pLogFile="$cRes" ; shift
   elif procParmL "--log-file" "$1" ; then
                pLogFile="$cRes"
   elif [ "$1" = "-u" ] ; then
                pUpdate=1
   elif [ "$1" = "--update" ] ; then
                pUpdate=1
   elif [ "$1" = "-sc" ] ; then
                pShowCmd=1
   elif [ "$1" = "--show-command" ] ; then
                pShowCmd=1
   elif [ "$1" = "-n" ] ; then
                pDryRun=1
   elif [ "$1" = "--dry-run" ] ; then
                pDryRun=1
   elif [ "$1" = "-bg" ] ; then
                pBackgr=1
   elif [ "$1" = "--background" ] ; then
                pBackgr=1
   elif [ -z "$1" ] ; then
      break # Ключи кончились
   else
      (( fixPrmCnt++ ))
      if   [ 1 -eq $fixPrmCnt ] ; then
         pSrcDir="$1"
      elif [ 2 -eq $fixPrmCnt ] ; then
         pDstDir="$1"
      else
         errMess "Ошибка: неизвестный ключ"
         exit 1
      fi
   fi
   shift
done

checkParm "$pSrcDir" "Не задана директория-источник"
checkParm "$pDstDir" "Не задана директория-приемник"

if [ "$pInter" = "1" ] && [ "$pYes" = "1" ] ; then
        errMess "Несовместимые параметры: --yes и -i"
        exit 1
fi

# Откусывыаем конечную слэш, если она задана
pSrcDir="${pSrcDir%/}"
pDstDir="${pDstDir%/}"

checkDir "$pSrcDir"
checkDir "$pDstDir"

# Если неинтерактивный запуск
if [ "$pInter" != "1" ] ; then

        # Запрос подтверждения
        if [ "$pYes" != "1" ] ; then
                echo "Скрипт ${curScript##*/} приветствует Вас!"
                showInfo
                myAskYesNo "Это может повлечь необратимые последствия! Вы уверены?" || exit
        fi

        createCmd

else
        cat <<EOF
Скрипт ${curScript##*/} приветствует Вас!
Точкой на любой вопрос Вы сможете прервать выполнение.
Выберите желаемый режим:
------------------------
   c) clone   (полное клонирование)
   u) update  (только обновление)
   .) Выход
EOF
        input1 "Твой выбор: " "cu." "dot-exit"

        pBackgr= # Чтобы не наложился параметр, заданный с командной строки
        input1 "Хотите ли Вы выполнить операцию копирования в фоне? (y/n): " "yn." "dot-exit"
        [ "$cRes" = "y" ] && pBackgr=1

        # А здесь может быть по умолчанию то, что пришло с командной строки
        read -p "Введите имя лог-файла (по умолчанию: $pLogFile): " a1
        [ -n "$a1" ] && pLogFile="$a1"

        pShowCmd= # Чтобы не наложился параметр, заданный с командной строки
        input1 "Вывести команду синхронизации на экран? (y/n): " "yn." "dot-exit"
        [ "$cRes" = "y" ] && pShowCmd=1

        createCmd

        echo
        showInfo

        if [ "$pShowCmd" = "1" ] ; then
                echo "Команда rsync:"
                echo "  $RSCmd" "${RSPrm[@]}"
        fi

        myAskYesNo "Запускаем! Вы уверены?" || exit
fi

if [ "$pBackgr" = "1" ] ; then
        nohup $RSCmd "${RSPrm[@]}" &
else
        $RSCmd "${RSPrm[@]}"
fi
К оглавлению

Библиотека функций

curPath=
cRes=
pYes=

myAskYN()
{
        local AMSURE
        if [ -n "$1" ] ; then
                read -n 1 -p "$1 (y/[a]): " AMSURE
        else
                read -n 1 AMSURE
        fi
        echo "" 1>&2
        if [ "$AMSURE" = "y" ] ; then
                return 0
        else
                return 1
        fi
}
myAskYNE()
{
        local AMSURE
        if [ -n "$1" ] ; then
                read -n 1 -p "$1 (y/[a]): " AMSURE
        else
                read -n 1 AMSURE
        fi
        echo "" 1>&2
        if [ "$AMSURE" != "y" ] ; then
                exit
        fi
}
myAskYesNo()
{
        local AMSURE
        if [ -n "$1" ] ; then
                read -p "$1 (YES/[any]): " AMSURE
        else
                read AMSURE
        fi
        if [ "$AMSURE" = "YES" ] ; then
                return 0
        else
                return 1
        fi
}
sayWait()
{
   local AMSURE
   [ -n "$1" ] && echo "$@" 1>&2
   read -n 1 -p "(нажмите любую клавишу для продолжения)" AMSURE
   echo "" 1>&2
}
cdAndCheck()
{
   cd "$1"
   if ! [ "$(pwd)" = "$1" ] ; then
      echo "!!Не могу встать в директорию $1 - продолжение невозможно. Выходим." 1>&2
      exit 1
   fi
}
checkDir()
{
   if ! [ -d "$1" ] ; then
      if [ -z "$2" ] ; then
         echo "!!Нет директории $1 - продолжение невозможно. Выходим." 1>&2
      else
         echo "$2" 1>&2
      fi
      exit 1
   fi
}
checkFile()
{
   if ! [ -f "$1" ] ; then
      if [ -z "$2" ] ; then
         echo "!!Нет файла $1 - продолжение невозможно. Выходим." 1>&2
      else
         echo "$2" 1>&2
      fi
      exit 1
   fi
}
checkParm()
{
   if [ -z "$1" ] ; then
                echo "!!$2. Продолжение невозможно. Выходим." 1>&2
      exit 1
   fi
}
input1()
{
        local a1 allowedSym

        allowedSym="$2"
        if [ "$3" = "dot-exit" ] ; then
                allowedSym="$allowedSym."
        fi

        if [ -n "$1" ] ; then
                read -p "$1" -sn 1 cRes
        else
                read -sn 1 cRes
        fi

        # Проверка допустимых выборов
        #a1="$allowedSym"
        while [ "$allowedSym" = "${allowedSym#*$cRes}" ] ; do
                read -sn 1 cRes
        done
        echo $cRes 1>&2
        if [ "$3" = "dot-exit" ] && [ "$cRes" = "." ] ; then
                exit
        fi
}
procParmS()
{
        [ -z "$2" ] && return 1
        if [ "$1" = "$2" ] ; then
                cRes="$3"
                return 0
        fi
        return 1
}
procParmL()
{
        [ -z "$1" ] && return 1
        if [ "${2#$1=}" != "$2" ] ; then
                cRes="${2#$1=}"
                return 0
        fi
        return 1
}
errMess()
{
        echo "$@" 1>&2
}
#--   padMid
# Объединение двух строк и заполнение пространства между ними точками типа:
#               Исходный файл................................myfile1.txt
#               Выходной файл................................myfile2.txt
#
# Параметры:
# 1 - Требуемый размер строки
# 2 - Первая строка
# 3 - Вторая строка
#
# Результат помещается в переменную $cRes
padMid()
{
        local len1 len2 lenDots dotStr

        len1=${#2}
        len2=${#3}
        lenDots=$1
        dotStr="................................................................................"
        ((lenDots=lenDots-len1-len2-1))
        if [ $lenDots -lt 0 ] ; then
                cRes="$2 $3"
        else
                cRes="$2${dotStr:0:$lenDots} $3"
        fi
}
outDelim80()
{
        echo "--------------------------------------------------------------------------------" 1>&2
}
transYesNoRu()
{
        if [ "$1" = "1" ] ; then
                cRes="Да"
        else
                cRes="Нет"
        fi
}
К оглавлению
  • Soft Space SIA
    Latvia
  • Этот адрес электронной почты защищен от спам-ботов. У вас должен быть включен JavaScript для просмотра.
  • +371 25 46 42 49
Big-IP Edge Client openconnect client cisco secure client download netextender download for mac wisenet viewer download admanager plus download globalprotect download citrix secure access watchguard ssl vpn download Qfinder Pro fortinet vpn forticlient mac