====== Скриптинг ======
Первой строкой указывается т.н. **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