Bash скрипты
Правила по написанию кода Bash скриптов описаны в руководствах Google Shell Style Guide и Apple Developer Shell Scripting Primer. Вкратце:
- В начале файла скрипта должна быть строка
#!/bin/bash - Отступы — 2 пробела.
- Комментарии отмечаются символом
# - Команды Bash вводятся каждая на отдельной строке или разделяются символом
;. Исключение составляют конвейеры: в них команды находятся в пределах одной строки и разделены символом|. При этом нужно понимать, что есть команды Bash и есть команды операционной системы. Например,echo— это команда операционной системы, аlet— команда Bash.
Символ \n позволяет добавить в строку перевод строки, как будто была нажата клавиша Enter.
Для использования управляющих символов с обратным слэшем (escape sequences, см. ниже в разделе «Цвет») нужно в команду echo добавлять аргумент -e:
echo -e "\nСтрока, перед которой стоит перевод строки."
read -p $'\n'"Вопрос к пользователю, перед которым стоит перевод строки. [Y/n] "
read -p "Вопрос к пользователю, разбитый на две строки."$'\n'"Вы уверены, что хотите это сделать? [Y/n] "
Команда echo по умолчанию добавляет в конец строки перевод строки. Чтобы его убрать, используйте параметр -n:
echo -n "Строка, после которой не будет перевода строки."
head -5 ${FILE} # Первые 5 строк
tail -5 ${FILE} # Последние 5 строк
tail -5 ${FILE} | tac # Последние 5 строк и отсортировать в обратном порядке
Добавить в массив незакомментированные строки (без знака # в начале строки):
while read LINE; do
ARRAY+=("$LINE")
done < <(grep '^[^#]' ${FILE})
Дописать в конец файла file.txt строку:
echo "Строка с текстом" >> file.txt
Дописать в конец файла file.txt несколько строк:
cat >>file.txt <<EOF
Первая строка
Вторая строка
Третья строка
EOF
То же самое с помощью sed:
sed -i '$ a \\nПервая строка\nВторая строка\nТретья строка' file.txt
Содержимое файла source.txt дописать в конец файла file.txt:
cat source.txt >> file.txt
Найти в переменной ${VAR} фрагмент template:
if [[ "${VAR}" =~ "template" ]]; then
echo "Найдено!"
fi
Проверить, имеет ли переменная ${VAR} значение one или two:
if [[ "${VAR}" =~ ^one$|^two$ ]]; then
echo "Найдено!"
fi
Найти в файле ${FILE} строку с фрагментом ${TEMPLATE}:
if grep -q "${TEMPLATE}" "${FILE}"; then
echo "Найдена строка с текстом '${TEMPLATE}'."
else
echo "Строк с текстом '${TEMPLATE}' не найдено."
fi
Сохранить в переменной ${STRING} строку из файла ${FILE}, содержащую фрагмент ${TEMPLATE}:
STRING=$(grep "${TEMPLATE}" "${FILE}")
Заменить в переменной ${VAR} фрагмент template на значение переменной ${REPLACE}:
VAR=`echo "${VAR}" | sed 's/^\(.*\)template\(.*\)$/\1'${REPLACE}'\2/'`
где регулярное выражение s/^\(.*\)template\(.*\)$/\1'${REPLACE}'\2/ разбирается следующим образом:
s— замена/ищем/заменяем/— общая структура регулярного выражения^— начало строки$— конец строки(.*)— здесь:.— любые символы, кроме перевода строки;*— в любом количестве;- скобки
(…)означают, что найденный фрагмент нужно сохранить во временной переменной\1(а содержимое второго набора скобок будет сохранено в переменной\2и т.д.) - В sed скобки экранируются обратными слэшами, поэтому полная запись получается
\(.*\)
\1'${REPLACE}'\2— здесь:\1— первая временная переменная'${REPLACE}'— внешняя переменная\2— вторая временная переменная
Для замены в URL или путях к файлам, содержащих слеши /, чтобы не получать из-за слешей ошибку unknown option to `s', можно использовать другой разделитель:
VAR=`echo "${VAR}" | sed 's|^\(.*\)template\(.*\)$|\1'${REPLACE}'\2|'`
Чтобы присвоить переменной фрагмент, найденный оператором =~, используем специальную переменную BASH_REMATCH:
if [[ "${VAR}" =~ ^(template).*$ ]]; then
TEMPLATE=${BASH_REMATCH[1]}
fi
VAR="$(echo -e "${VAR}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
Специальная последовательность \u переводит следующий за ней один символ в верхний регистр.
Аналогичная последовательность \l переводит один следующий символ в нижний регистр.
Последовательности \U или \L переводят все символы в верхний и нижний регистр, пока не встретится \E или не закончится строка подстановки.
# Сделать первую букву слова заглавной:
# WORD=`upfirst ${WORD}`
upfirst() {
echo -n ${1:0:1} | sed 's/[[:lower:]]/\u&/g'
echo ${1:1}
}
# Сделать первую букву слова строчной:
# WORD=`lowfirst ${WORD}`
lowfirst() {
echo -n ${1:0:1} | sed 's/[[:upper:]]/\l&/g'
echo ${1:1}
}
http://freaksidea.com/show-39-uchimsia-proghrammirovat-v-shell-manipuliatsii-s-peremennymi
Конкатенация переменной:
second=$first' is a var'
let "c=a+b" # Сложение
let "a+=b" # Эквивалентно 'let "a=a+b"'
let "index+=1"
Увеличение значения счетчика на единицу:
((i++))
i=$(($i+1))
let "i+=1"
[ "$a" -eq "$b" ] && echo "$a равно $b"
[ "$a" -ne "$b" ] && echo "$a не равно $b"
[ "$a" -gt "$b" ] && echo "$a больше, чем $b"
(( "$a" > "$b" )) && echo "$a больше, чем $b"
[ "$a" -ge "$b" ] && echo "$a больше или равно $b"
(( "$a" >= "$b" )) && echo "$a больше или равно $b"
[ "$a" -lt "$b" ] && echo "$a меньше, чем $b"
(( "$a" < "$b" )) && echo "$a меньше, чем $b"
[ "$a" -le "$b" ] && echo "$a меньше или равно $b"
(( "$a" <= "$b" )) && echo "$a меньше или равно $b"
[ "$a" = "$b" ] && echo "$a равно $b"
[ "$a" == "$b" ] && echo "$a равно $b"
== является синонимом оператора =.
[[ $a == z* ]] # истина, если $a начинается с символа "z" (сравнение по шаблону)
[[ $a == "z*" ]] # истина, если $a равна z*
[ "$a" == "z*" ] # истина, если $a равна z*
[ $a == z* ] # подстановка имен файлов и разбиение на слова
[ "$a" != "$b" ] && echo "$a не равно $b"
[ "$a" == "$b" ] && echo "$a равно $b"
[[ "$a" < "$b" ]] && echo "$a меньше, чем $b (в смысле величины ASCII-кодов)"
[ "$a" \< "$b" ] && echo "$a меньше, чем $b (в смысле величины ASCII-кодов)"
[[ "$a" > "$b" ]] && echo "$a больше, чем $b (в смысле величины ASCII-кодов)"
[ "$a" \> "$b" ] && echo "$a больше, чем $b (в смысле величины ASCII-кодов)"
Обратите внимание! Символы < и > необходимо экранировать внутри одинарных квадратных скобок [ ].
Функция, которая получает в качестве аргумента имя переменной и выводит на экран и имя переменной и её значение:
variable() {
local NAME=$1
local VALUE=$(eval 'echo -n "$'${NAME}'"')
echo "${NAME} = '${VALUE}'"
}
$? — специальная переменная, в которой хранится код возврата последней команды. По-английски называется exit code или exit status.
Если код возврата равен 0, то команда выполнена успешна. Любые другие значения указывают на какую-то ошибку.
Примеры кодов ошибок:
- 1: общие ошибки;
- 2: ошибки работы встроенных средств оболочки;
- 126: невозможно вызвать запрошенную команду;
- 127: команда не найдена;
- 128: некорректный аргумент exit;
- 128 + n: сигнал критической ошибки (например, kill -9 = 137);
- 130: скрипт прерван по Ctrl+C.
Пример использования кода возврата:
mkdir /usr
if [ $? -ne 0 ] ; then
echo "\$? = $?"
echo "mkdir /usr failed: we have an exit code of $?"
else
echo "\$? = $?"
echo "made the requested directory. Why is '/' world writable?"
fi
Из-за того, что каждая следующая команда (даже echo) перезаписывает переменную $?, иногда полезно сразу сохранить ее значение в собственную переменную:
mkdir /usr
status=$?
if [ $status -ne 0 ] ; then
echo "mkdir /usr failed: we have an exit code of $status"
fi
Или использовать собственную функцию:
# Use: test command
test() {
"$@"
local status=$?
if [ $status -ne 0 ]; then
echo "error with $1" >&2
fi
return $status
}
command -v vim
-z ${VAR+x} — переменная $VAR не определена (подробнее):
if [ -z ${VAR+x} ]; then
echo "VAR не определена"
else
echo "VAR определена как '$VAR'"
fi
-z — переменная пуста:
[ -z "${VAR}" ] && echo "Переменная VAR пуста"
-n — переменная имеет значение:
[ -n "${VAR}" ] && echo "Переменная VAR имеет значение '${VAR}'"
[ "${#ARRAY[@]}" -eq 0 ] && echo "Массив ARRAY пуст"
if drush status | grep -q Connected; then
echo "Подключение к базе данных есть"
fi
echo "PWD = ${PWD}" # полный путь к текущему рабочему каталогу
echo "OLDPWD = ${OLDPWD}" # предыдущий рабочий каталог
echo "CDPATH = ${CDPATH}" # пути поиска каталога (используется при вводе команды cd имя_каталога без слэша)
echo "HOME = ${HOME}" # путь к домашнему каталогу пользователя
echo "PATH = ${PATH}" # список каталогов для поиска команд и приложений, когда полный путь к файлу не задан
echo "DIRSTACK = ${DIRSTACK}" # содержимое вершины стека каталогов (который управляется командами pushd и popd)
FILE_PATH="/path/to/file.txt" # Полный путь к файлу
DIR_PATH=$(dirname "${VAR}") # Путь к файлу: "/path/to"
FILENAME_EXT=$(basename "${FILE_PATH}") # Имя файла с расширением: "file.txt"
FILENAME=$(basename "${FILE_PATH}" .txt) # Имя файла без расширения: "file"
EXTENSION="${FILENAME_EXT##*.}" # Расширение: "txt"
Подробнее: Extract filename and extension in Bash
while read DIR; do
echo "$DIR"
done < <(ls -d */ | sed 's|/||g')
-e — файл существует
-f — обычный файл (не каталог и не файл устройства)
-s — файл существует и его размер больше нуля
-d — каталог
-h — символическая ссылка
-L — символическая ссылкой
-r — доступен для чтения (пользователю, запустившему сценарий)
-w — доступен для записи (пользователю, запустившему сценарий)
-x — доступен для исполнения (пользователю, запустившему сценарий)
-b — блочное устройство (floppy, cdrom и т.п.)
-c — символьное устройство (клавиатура, модем, звуковая карта и т.п.)
-p — канал
[ ! -f "$FILE" ] && echo 'Файл не существует'
[ ! -e "$FILE" ] && echo "Файл не найден"
[ ! -d "$DIR" ] && echo "Папка не существует"
! [[ -d "$DIR" && -w "$DIR" ]] && echo "Папка не существует или нет прав для записи"
Альтернативный вариант — с помощью команды ls. Позволяет использовать маску:
if ls ${PATH} 1> /dev/null 2>&1; then
echo "Папка ${PATH} существует."
else
echo "${PATH} не существует."
fi
Пустая ли папка:
if `ls -A "${PATH}" | wc -l` -eq 0; then
echo "Папка ${PATH} пустая."
fi
Количество файлов и папок:
ls -A | wc -l
Получить список только папок:
ls -d */ | sed 's/\///g'
Проверить, есть ли в субдиректории:
if (( "$(ls -la . | grep '^d' | wc -l)" <= 2 )); then
echo "Субдиректорий нет"
else
echo "Есть субдиректории"
fi
Создать файл с уникальным именем в папке /tmp и сохранить имя файла в переменной TEMPFILE:
TEMPFILE="$(mktemp)"
Универсальная (будет работать и в Linux и в Mac OS X) команда для создания временной директории с гарантированно уникальным именем и сохранения ее имени в переменной:
TEMPDIR=`mktemp -d 2>/dev/null || mktemp -d -t 'mytmpdir'`
Определить массив:
ARRAY=()
или
declare -a ARRAY
Поместить несколько элементов в массив:
ARRAY=(
"element1"
"element2"
"element3"
)
Добавить в массив один элемент:
ARRAY+=("element4")
Добавить в массив элемент с ключом 0 (т.е. поставить его в начало массива):
ARRAY[0]='element1'
Поместить в массив список файлов (т.е. вывод команды ls):
ARRAY=(`ls`)
То же самое по одному элементу:
i=0
while read line; do
ARRAY[$i]="$line"
((i++))
done < <(ls)
Поместить в массив строки из файла — то же самое, но последняя строка:
done < filename
Показать все элементы массива в строку:
echo "${ARRAY[@]}"
Показать все элементы массива в столбик:
for ELEMENT in "${ARRAY[@]}"; do
echo "${ELEMENT}"
done
Или с нумерацией (при выводе нумерации увеличиваем каждый номер на единицу, чтобы начинать не с нуля):
for ((i=0; i < ${#ARRAY[*]}; i++)); do
n=$(($i+1))
echo "$n. ${ARRAY[$i]}"
done
Показать первый элемент:
echo "${ARRAY[0]}"
Показать последний элемент:
echo "${ARRAY[-1]}" # Не работает в Mac OS X
echo "${ARRAY[*]: -1}"
Проверить, массив пустой или содержит элементы:
if [ "${#ARRAY[@]}" -eq 0 ]; then
echo "Массив пустой"
else
echo "В массиве ${#ARRAY[@]} элементов"
fi
# Usage: 'element_exists array element'
# Возвращает 1, если элемент существует.
element_exists() {
# Массив, в котором проверяем наличие элемента
declare -a ARRAY=("${!1}")
# Элемент, который ищем в массиве
ARRAY_ELEMENT=$2
for i in ${ARRAY[@]}; do
if [[ "${i}" == "${ARRAY_ELEMENT}" ]]; then
return 1
break
fi
done
return 0
}
Выполнить функцию foo только в том случае, если она существует:
declare -F foo &>/dev/null && foo
echo "Количество аргументов: $#"
args=$#
echo "Последний аргумент: ${!args}"
# Обратите внимание: ${!$#} — неприменимо.
echo "Все аргументы в виде одной строки: $*"
echo "Все аргументы в виде набора строк: $@"
# $@ — то же самое, что и $*, но при этом каждый параметр представлен как отдельная строка (слово),
# т.е. параметры не подвергаются какой-либо интерпретации.
Удаление первого аргумента:
shift
index=1
for arg in "$@"; do
echo "Аргумент $index: $arg"
let "index+=1"
done
testfun() {
echo "Аргумент №1: \$1 = $1"
echo "\$* — все аргументы в виде одной строки: $*"
echo "\$@ — все аргументы в виде набора строк: $@"
echo "В переменной \"\$*\" список аргументов хранится как одна строка:"
index=1
for arg in "$*"; do # Обязательно заключать "$*" в кавычки
echo "Аргумент $index: $arg"
let "index+=1"
done
echo "В переменной \"\$@\" список аргументов хранится как набор строк:"
index=1
for arg in "$@"; do
echo "Аргумент $index: $arg"
let "index+=1"
done
}
Запуск функции:
testfun один два три четыре
Результат:
Аргумент $1: один $@: один два три четыре $*: один два три четыре В переменной "$*" список аргументов хранится как одна строка: Аргумент 1: один два три четыре В переменной "$@" список аргументов хранится как набор строк: Аргумент 1: один Аргумент 2: два Аргумент 3: три Аргумент 4: четыре
# Функция, которая выводит список элементов массива, полученного в виде аргумента:
foo() {
# Поместим все аргументы в один массив ARG_ARRAY:
local ARG_ARRAY=("$@")
# Выведем элементы массива ARG_ARRAY в строку:
echo -e "\nМассив в строку:\n"
echo "${ARG_ARRAY[@]}"
# Выведем элементы массива ARG_ARRAY в столбик с нумерацией:
echo -e "\nМассив в столбик:\n"
n=1
for ELEMENT in "${ARG_ARRAY[@]}"; do
echo "$n) $ELEMENT"
((n++))
done
# Выведем отдельные элементы массива ARG_ARRAY:
echo -e "\n\${ARG_ARRAY[0]} - Элемент 1: ${ARG_ARRAY[0]}"
echo -e "\${ARG_ARRAY[1]} - Элемент 2: ${ARG_ARRAY[1]}"
echo -e "\${ARG_ARRAY[-1]} - Последний элемент: ${ARG_ARRAY[-1]}"
}
# Добавим в массив элементы:
ARRAY=(
"element1"
"element2"
)
# Переменная:
VAR="element3.1 element3.2"
# Передаем массив, переменную и пару простых аргументов в функцию:
foo "${ARRAY[@]}" "$VAR" "element4" "element5.1 element5.2"
declare -a ARGUMENT=("${!1}")
COUNT=${#ARGUMENT[@]}
if [[ "${COUNT}" == 1 ]]; then
echo "В \$1 находится одна переменная: '$1'"
else
echo "В \$1 находится массив из ${COUNT} переменных:"
for ((a=0; a < ${#ARGUMENT[*]}; a++)); do
echo " - ${ARGUMENT[$a]}"
done
fi
С чистым полем ввода:
read -p "Домен сайта: "
С возможностью редактирования подставленного по умолчанию текста:
DOMAIN="example.com"
read -e -p "Домен сайта: " -i "${DOMAIN}"
Срабатывание после нажатия одной клавиши:
while true; do
read -p "Вы уверены, что хотите сделать это? [y/n] " CASE
case ${CASE} in
[YyДд]*) echo "Да, сделаем это!"; break ;;
[NnНн]*) echo "Ничего не делаем."; break ;;
*) echo "Пожалуйста, нажмите y или n" ;;
esac
done
Срабатывание после набора правильного ответа и нажатия Enter — или просто нажатия Enter, что равно выбору варианта по умолчанию (в этом примере помеченного заглавнрй Y):
while true; do
read -p "Вы уверены, что хотите сделать это? [Y/n] "
if echo ${REPLY} | grep -qi "^y$\|^yes$\|^д$\|^да$\|^$"; then
echo "Да, сделаем это!"
break
elif echo ${REPLY} | grep -qi "^n$\|^no$\|^н$\|^нет$"; then
echo "Ничего не делаем."
break
else
echo "Пожалуйста, нажмите y или n"
fi
done
Часто алиасы по умолчанию отключены в bash скриптах, и поэтому команды вида alias ll="ls -l" не работают.
Чтобы включить алиасы в Bash скрипте, достаточно добавить в начале скрипта строку:
shopt -s expand_aliases
Алиас на выход из скрипта как в vim:
alias :q='tput setaf 1; echo >&2 "This is NOT vi(m) :/"; tput sgr0'
- Функция для чтения INI-файлов
- BASH. Чтение и запись строки без изменений
- BASH Parsing variables from config file
- Написание bash-сценариев
- System Administration Toolkit: Максимальное использование оболочки bash
- The OpenNET Project: Пример работы с MySQL в bash скриптах
Сохранить содержимое экрана и очистить его, выполнить работу, выждать 5 секунд и затем восстановить сохраненный экран:
tput smcup # Save the display
echo 'Hello, World!' # Work hard
sleep 5 # Wait five seconds
tput rmcup # Restore the display
Перемещение курсора:
tput cup Y X # Переместить курсор в позицию Y X (верхний левый угол: 0 0)
tput sc # Запомнить позицию курсора
tput rc # Восстановить позицию курсора
tput lines # Вывести количество строк на экране терминала
tput cols # Вывести количество колонок на экране терминала
tput cub N # Переместить курсор на N символов влево
tput cuf N # Переместить курсор на N символов вправо
tput cuu N # Вверх на N строк
tput cud N # Вниз на N строк
tput hpa X # Передвинуть курсор в позицию X
$(tput hpa $(tput cols) # Передвинуть курсор в конец строки
Скрыть и снова показать курсор:
tput civis # скрыть курсор
tput cnorm # показать курсор
Очистка:
el # Очистить от курсора до конца строки
el1 # Очистить от курсора до начала строки
ed # Очистить от курсора до конца экрана
clear # Очистить экран и поместить курсор в левый верхний угол
Вывести текст по центру предпоследней строки внизу экрана:
echo_bottom_center() {
echo `tput cup $(($(tput lines))) $(( ($(tput cols) - $(echo "${#1}"))/2 ))`"$1"`tput cup $(tput lines) $(( $(tput cols)-1 ))`;
}
echo_bottom_center "Bottom Center Text."
Вывести текст по центру экрана:
echo_vertical_center() {
echo `tput cup $(($(tput lines)/2)) $(( ($(tput cols) - $(echo "${#1}"))/2))`"$1"`tput cup $(tput lines) $(( $(tput cols)-1 ))`;
}
echo_vertical_center "Vertical Center Text."
Вывести и обновлять время и дату справа внизу:
echo_time() {
echo `tput cup $(($(tput lines)-2)) $(($(tput cols)-$(echo ${#1})))&&tput sc`"$1"`tput cup $(($(tput lines)-2)) 0 && tput rc`;
}
while [ 1 ]; do
echo_time "`date`"
done
Вывести строку из звездочек шириной в экран терминала:
seq -s'*' 0 $(tput cols) | tr -d '[:digit:]'
Еще примеры tput:
http://misc.flogisoft.com/bash/tip_colors_and_formatting
Для отображения цветного и выделенного текста в Bash используются escape sequences (эскейп последовательности, управляющие последовательности, экранированные последовательности).
Шаблон управляющей последовательности: <Esc>[FormatCodem
В синтаксисе Bash для обозначения <Esc> можно использовать один из трех вариантов:
\e– не работает в Mac OS X\033\x1B
Команда echo по умолчанию не обрабатывает управляющие последовательности. Чтобы включить это, нужно использовать параметр '-e': echo -e.
Для очистки всех атрибутов применяется управляющая последовательность 0 (в полном виде: \e[0m). Имеет смысл ставить ее в конце каждого выделенного текста.
Примеры:
echo -e "Normal \e[1mBold\e[0m" # 1 - Полужирный
echo -e "Normal \e[2mDim\e[0m" # 2 - Приглушенный
echo -e "Normal \e[4mUnderlined\e[0m" # 4 - Подчеркнутый
echo -e "Normal \e[5mBlink\e[0m" # 5 - Мигающий
echo -e "Normal \e[7mInverted\e[0m" # 7 - Инвертированный
Текстовый интерфейс форм с чекбоксами и т.п. Альтернатива для dialog. Не поддерживает мышь и часть виджетов dialog'а, но работает надёжнее без глюков. Также, в отличие от dialog, во многих дистрибутивах устанавливается по умолчанию.
Графический интерфейс, Zenity On Steroids.
http://brettterpstra.com/2015/02/20/shell-trick-printf-rules/
- Отладка сценариев
- Bash Bits: Debug Logging - Raymii.org
- BASH: использование команды trap для перехвата сигналов прерывания процесса
Получить список всех встроенных переменных:
printenv
Информация о системе
echo "HOSTTYPE=\"${HOSTTYPE}\"" # тип машины
echo "OSTYPE=\"${OSTYPE}\"" # тип операционной системы
echo "HOSTNAME=\"${HOSTNAME}\"" # сетевое имя компьютера
echo "USER=\"${USER}\"" # имя текущего пользователя
echo "UID=\"${UID}\"" # реальный идентификатор (UID) текущего пользователя в соответствии с /etc/passwd,
# даже если он временно приобрел права другого пользователя с помощью su.
echo "BASH_VERSION=\"${BASH_VERSION}\"" # полный номер версии Bash
echo "BASH_VERSINFO[0]=\"${BASH_VERSINFO[0]}\"" # мажорный номер версии Bash
Настройки
echo "IFS=\"${IFS}\"" # символы, являющиеся разделителями команд и параметров
# (по умолчанию — пробел, табуляция и новая строка)
echo "OPTERR=\"${OPTERR}\"" # если имеет значение 1, bash показывает сообщения об ошибках,
# выдаваемые встроенной командой getopts. По умолчанию 1.
Отладка
echo "FUNCNAME=\"${FUNCNAME}\"" # имя массива, содержащего имена всех функций выполняемых в настоящее время.
echo "LINENO=\"${LINENO}\"" # номер строки исполняемого сценария
echo "REPLY=\"${REPLY}\"" # переменная по умолчанию, куда записывается ввод пользователя,
# выполненный с помощью команды read, если явно не задана другая переменная.
# Также может использоваться в операторе select для построения меню выбора.
echo "SECONDS=\"${SECONDS}\"" # время работы сценария в секундах
Перехват выхода из скрипта по CtrlC:
trap '' 2 # Сигнал 2 (Ctrl-C) запрещен
trap 2 # Разрешение реакции на Ctrl-C
Пример: по CtrlC сначала выполнить команду echo "Exit" и только потом выйти с кодом 1.
trap 'echo "Exit"; exit 1' 2
while [ $count -lt 10 ]; do
sleep 1
(( count++ ))
echo $count
done
- Google: Shell Style Guide
- Google Chromium OS: Shell Style Guidelines
- Apple Developer: Shell Scripting Primer
- Gentoo Development Guide: bash -- Standard Shell
- BashGuide/Practices - Greg's Wiki
- Приемы написания скриптов в Bash / Хабрахабр — особенно комментарии