Функции в bash
Объявление функций, аргументы $1 $@ $#, local, return и вывод результата, source и export -f
Функция в bash — именованный кусок кода, который вызывают как обычную команду: имя арг1 арг2. Функции убирают повторы в скриптах, а вынесенные в отдельный файл и подключённые через source становятся библиотекой. У функции нет объявленных параметров и возвращаемого значения в привычном смысле: аргументы приходят в $1, $2, …, а наружу она отдаёт код возврата и то, что напечатала в stdout.
Синтаксис
имя() { # основная форма (POSIX)
команды
}
function имя { # форма bash; работает и function имя() { … }
команды
}
имя() ( команды ) # тело в круглых скобках выполняется в подоболочке
имя арг1 "арг 2" # вызов
Функцию нужно объявить до первого вызова. Однострочная запись требует ; перед }: hi() { echo hi; }.
Аргументы внутри функции
| Запись | Что это |
|---|---|
$1 … $9, ${10} | позиционные аргументы функции (с десятого — только в фигурных скобках) |
$# | количество аргументов |
"$@" | все аргументы, каждый — отдельным словом, с сохранением пробелов внутри |
"$*" | все аргументы одной строкой через первый символ $IFS (пробел) |
${@: -1} | последний аргумент |
shift / shift N | сдвинуть аргументы: $2 становится $1 и т. д. |
$0 | имя скрипта (или bash), а не функции |
${FUNCNAME[0]} | имя текущей функции; ${FUNCNAME[1]} — того, кто её вызвал |
Аргументы скрипта внутри функции не видны: $1 в функции — это первый аргумент функции. Чтобы передать аргументы скрипта, вызови f "$@".
Переменные: глобальные и local
| Запись | Что делает |
|---|---|
x=1 | без объявления переменная глобальная: видна и меняется во всём скрипте |
local x=1 | переменная видна только в этой функции и в функциях, которые она вызывает |
local -a arr / local -A map / local -i n | локальный массив / ассоциативный массив / целое |
declare x=1 (внутри функции) | то же, что local |
declare -g x=1 | явно глобальная переменная изнутри функции |
Как вернуть результат
| Способ | Пример | Когда |
|---|---|---|
| код возврата | return 0 / return 1 | «да/нет», «успех/ошибка»; число 0–255 |
| печать в stdout | echo "$res", затем x=$(f) | вернуть строку или число |
| глобальная переменная | RESULT=… | без подоболочки, но функция и вызывающий код связаны |
| ссылка на переменную | local -n out=$1; out=… | записать результат в переменную, имя которой передано аргументом |
Без return функция возвращает код последней выполненной команды.
Управление функциями
| Команда | Что делает |
|---|---|
declare -F | список имён объявленных функций |
declare -f имя / type имя | показать тело функции |
unset -f имя | удалить функцию |
export -f имя | передать функцию дочерним процессам bash |
source файл / . файл | выполнить файл в текущей оболочке: его функции и переменные остаются доступными |
Примеры
# простая функция с аргументами и значением по умолчанию
greet() {
local name=${1:-мир}
echo "Привет, $name!"
}
greet # Привет, мир!
greet Анна # Привет, Анна!
# функция-проверка: результат — код возврата
is_number() {
[[ $1 =~ ^[0-9]+$ ]]
}
if is_number 42; then echo "число"; fi
# функция возвращает строку через stdout
to_upper() {
echo "${1^^}"
}
name=$(to_upper "hello") # HELLO
# сообщение об ошибке — в stderr, чтобы не попасть в $(…)
die() {
echo "ошибка: $*" >&2
exit 1
}
[[ -f /etc/hosts ]] || die "нет /etc/hosts"
# перебрать все аргументы с сохранением пробелов
show_args() {
echo "аргументов: $#"
for a in "$@"; do echo "<$a>"; done
}
show_args "один два" три
# вернуть значение в переменную по имени (nameref)
get_size() {
local -n _out=$1
_out=$(wc -c < "$2")
}
get_size bytes /etc/hostname
echo "$bytes"
# библиотека функций в отдельном файле
cat > /tmp/lib.sh <<'EOF'
log() { echo "[$(date +%T)] $*"; }
EOF
source /tmp/lib.sh
log "запуск"
# функция, доступная дочернему bash (например, в xargs или find -exec)
check() { echo "проверяю $1"; }
export -f check
printf '%s\n' a b | xargs -I{} bash -c 'check "$1"' _ {}
Подводные камни
- Переменные по умолчанию глобальные. Присваивание
i=…внутри функции перезапишетiво внешнем цикле. Объявляй рабочие переменные черезlocal. return— только код 0–255.return 300вернёт44(остаток от деления на 256). Строки и большие числа возвращай черезechoи$(…).- Всё, что функция печатает, попадёт в
$(f). Отладочные и диагностические сообщения пиши в stderr:echo "…" >&2. $(f)выполняет функцию в подоболочке. Изменения переменных иcdвнутри неё наружу не выйдут.local x=$(cmd)теряет код возвратаcmd.$?после такой строки — код самой командыlocal, то есть 0. Если код важен, раздели:local x; x=$(cmd).$*и$@без кавычек режут аргументы по пробелам. Аргумент"один два"превратится в два. Пиши"$@".set -eне работает внутри функции, вызванной в условии. Приf || echo failиif f; thenошибки команд внутриfигнорируются, и функция выполняется до конца.export -fпонимает только bash.sh -c имяскажетnot found:shв Ubuntu — этоdash.source lib.shищет файл сначала в$PATH, потом в текущем каталоге — текущем для того, кто запустил скрипт, а не в каталоге самого скрипта. Запусти скрипт из другого места — и библиотека не найдётся. Пиши путь от скрипта:source "$(dirname "$0")/lib.sh".
См. также
variables · exit-codes · getopts · set · conditions-loops