====== Скриптинг ====== Первой строкой указывается т.н. **shebang (#!)** - последовательность двух символов, далее указывается путь к исполняющему файлу под-оболочки, так же, в этой строке можно передавать аргументы.\\ Если оболочка не указана явно, используется так же, что и запускает данный скрипт.\\ Для исполнения скрипта, у файла должно быть разрешение выполнения (**+x**), но если передать скрипт аргументом команде **bash ./script**, тогда бит необязателен.\\ **exit** - сообщает результат **(0-успех)** работы родительскому процессу, при отсутствии используется результат последней команды.\\ ===== Аргументы (доступ к ним) ===== * **$?** - код возврата последней выполнившейся команды * **$$** - номер процесса последней команды ($! фоновой) * **$№** - аргументы, по номеру. &0 - последний запущенный скрипт. * **$#** - кол-во переданных аргументов. * **$*** - все аргументы одной строкой. * **$@** - все аргументы отдельной строкой. * **$-** - дейтствующие пар-ры команды **set** * **shift** - команда, после нее первый аргумент в $@ теряется, остальные сдвигаются влево. ===== Переменные ===== **Пробелы не используются при определении**\\ Знак доллара используется только **при чтении** значения, работа с переменной без этого знака.\\ В фигурных скобках более строгая форма ${variable}.\\ **Двойные кавычки** - "нестрогие", и не влияют на механизм подстановки, в отличии от **одинарных кавычек**.\\ Конкатенация строк происходит без дополнительных символов: **$Val1"_"$Val2**. ${переменная/шаблон/замена} - замена первого совпадения ${переменная/шаблон} - удалить первое совпадение ${переменная//шаблон/замена} - замена каждого совпадения (# в начале, % в конце переменной) ${string:position [:length] } - подстрока ${переменная:-значение} - значение по умолчанию для переменной ${переменная:=значение} - если переменной нет то присваиваем значение ${переменная:?значение} - использовать переменную если установлена, либо выйти с ошибкой (значение) ${переменная:+значение} - использовать значение если переменная установлена, иначе ничего ${переменная#шаблон} - значение переменной после удаления шаблона слева, самый короткий (## самый длинный) (% %% тоже самое только справа) ==== Массивы ==== **Индексные**\\ Инициализируется перечнем значений в круглых скобах, через пробел. Работает **отрицательный индекс**\\ a=(0 1 2 3 4 5) # Первый / Четвертый / предпоследний элемент / второй ${a}; ${a[4]}; ${a[-2]}; ${a[3-1]} # Все элементы массива ${arr[*]}; ${arr[@]}; # Ряд элементов массива ${#arr[]}; ${#arr[]}; # Длина массива ${#arr[@]} **Ассоциативные**\\ # Объявить так declare -A arr arr[index_foo]=value_foo arr[index_bar]=value_bar arr[index_xyz]=value_xyz # Либо так array_name=( [index_foo]=value_foo [index_bar]=value_bar [index_xyz]=value_xyz ) # Перебор массива должен быть таким # Обязательно с воскл знаком, иначе не те значения for key in ${!from_49[@]}; do ==== Встроенные переменные ==== * **$BASH** - путь к исполняемому файлу bash. * **$GROUPS** - группы пользователя. * **$HOME ** - домашний каталог. * **$HOSTNAME ** - сетевое имя хоста. * **$SHLVL ** - уровень вложенности shell. * **$SECONDS** - время работы скрипта. * **$REPLY** - для ввода read, по умолчанию. ===== Условие ===== **Двойные квадратные скобки** работают в целом так же, как и [одинарные квадратные скобки], но имеют дополнительные возможности вроде лучшей поддержки регулярных выражений.\\ **Двойные круглые скобки** это конструкция, позволяющая осуществлять арифметические вычисления внутри Bash.\\ if [[ "$name" == "Ryan" ]] && ! [[ "$time" -lt 2000 ]]; then elif [[ "$day" == "New Year's Eve" ]] || [[ "$coffee_intake" -gt 9000 ]]; then else fi if [ "$age" -gt 30 ]; then echo "What an oldy." fi (( count++ )) echo "$count" if (( -57 + 30 + 27 )); then echo "First one" echo $(( (5 > 3) + (0 == 0) )) # В условии можно использовать **код завершения любой команды**\\ if grep -q coffee dialogue.txt; then .. fount/not found; fi if cmp a b &> /dev/null; then ... fi
:!: Old Проверяет, является ли результат **0 (истина)**.\\ Условие условие проверяется с помощью команды [[main:linux:bash:утилита_test|test]], на данный момент, команда **является встроенной** т.е. не вызывает аналогичную утилиту.\\ Условия можно указать следующими способами: * **if test -z $1** * **if /usr/bin/test -z $1** * **if [ -z $1 ]** * **if /usr/bin/[ -z $1** * **if [[ -z $1 ]']** - расширенный вариант простых скобок. Внутри допустимы операторы && || < и >. * **[ -z $1 ]** - условие может быть проверено из без оператора **if** * **() или двойные** - выполняет арифметическое действие внутри. **Код возврата противоположен []** Условный оператор проверяет код завершения **любой команды**, а не только результат выражения скобок. if cmp a b then echo "Файлы идентичны" else echo "Файлы различаются" fi Оператор **if** можно и не использовать. [ -z $1 ] && echo result false или ping -c 1 8.8.8.8 &>/dev/null || echo not available ==== Else if (elif) ==== **elif** - краткая форма записи конструкции **else if**. if [ expr ]; then action elif [ expr ]; then action else action fi
===== Циклы ===== ==== for ==== Обработка диапазонных значений.\\ **for** условие **do** действие **done**. for (( i=100; i>1; 1-- )); do action; done Внутри **((..)')** вычисляется арифметическое выражение и возвращается результат и позволяет работать с переменными в стиле С. Так же, можно указать диапазон\\ for i in {100..104}; do action; done for i in 100 101 102 103 104; do action; done for i in $@; do action; done numbers="1 2 3 4 5" for i in `echo $numbers`; do action; done # Перебор массива, выполнение команды с каждым элементом list=(user1 user2 user3 user4 user5 user6) for i in ${list[*]}; do printf '\n=======%s\n', $i influx -execute 'show grants for '$i';' -username '' -password '' done ==== while ==== Выполняется пока условие истинно.\\ **while** условие **do** действие **done**. В двойных скобках символ **$** перед переменной можно опустить, так же, двойные скобки позволяют наращивать значение переменной **( (v+=1) )** while [ $v1 -le $v2 ] do done while (( v1 <= v2 )') ; do action; done
:!: Примеры Бесконечный цикл while true do echo "--==" $(uname -a) "==--" sleep 2 done
==== Until ==== Противоположно циклу **while**, выполняется пока условие ложно. **until** условие **do** действие **done**. Все остальное аналогично. ===== case ===== case $v1 in val1) action1;; val2) action2;; *) default action;; esac ===== Работа со строками ===== # Длина строки echo ${#string} echo `expr length $string` ===== Отладка ===== Для отладки, можно использовать команду **bash -x файл_скрипта**. ===== Примеры ===== **"Около-многопоточность"**\\ Используется минимум два скрипта, в первом выполнение работы, второй в цикле запускает подоболочку в фоне, не дожидаясь окончания каждого. Ньюанс в том что в конце головной скрипт не закрывается сам, думаю можно исправить аргументами. for CurrAddr in {1..25}; do ./oneping $CurrAddr & # Там происходит просто пинг переданного адреса done # В итоге, ждем тайм-аут один раз, для всех хостов
:!: Случайные значения **Записать случайные байты в файл**\\ head -c 1024 /dev/urandom > file dd if=/dev/urandom of=file bs=100M count=1 iflag=fullblock # только печатные символы tr -dc 'a-zA-Z0-9' < /dev/urandom | head -c 100M > file # либо base64 вместо tr, только менее гибко по символам base64 < /dev/urandom | head -c 1024 (1K/1M) # ${RANDOM} - возвращает случайное число 0..32К # случайное число от 1..10, (1+ чтобы небыло ноля) $(1 + ${RANDOM} % 10) # Еще так можно диапазон возвращать # 1..5, вернуть одно число $(shuf -i 1-5 -n 1)
===== Утилита test ===== Unix утилита для проверки типа файла и сравнения значений.\\ Возвращает 0 (истина) или 1 (ложь). Выражения могут быть как унарными так и бинарными.\\ # Использование test [expr] if test -f file.txt или [ -f file.txt ] then rm file.txt else echo 'no found' fi ==== Параметры запуска ==== * **-d file** - если file существует и является директорией. * **-e file** - если file существует. * **-f file** - если file существует и является обычным файлом. * **-k file** - если file существует и ему установлен "sticky" бит. * **-L file** - если file существует и является символьной ссылкой. * **-r (-w/-x) file** - если file существует и читаем (записываем/исполняем). * **-z str** - если длина 0. * **-n str** - если длина не 0. * **-a (-o)** - аналог && (||) в одинарных скобках. * **str1 = ('!=') str2** - если строки равны (не равны). ===== Функции. Возврат значения ===== **function_name() {command... }**\\ Объявляются раньше вызова, **нет возможности предобъявления**\\ **return** возвращает только интовое значение, до 255\\ ===== Примеры =====
:!: Обширный пример {{ :linux:overall:bash:makeimport_sh.doc |}}
:!: Проверка PID # Такая конструкция сохранит ПИД последнего запущенного процесса в файл & echo $! > file.pid #!/bin/bash status=2 for i in 1 2 3 do # Для kill нужны права #if kill -0 `cat /path/file.pid` &> /dev/null; if ps -p `cat /path/file.pid` > /dev/null then status=0 break fi sleep 1 done echo "Service status is $status" exit $status