← Весь справочник

Функции в 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
печать в stdoutecho "$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