Как и во многих языках программирования, командный интерпретатор имеет средства структуризации сценариев при помощи функций. Составной именованный список команд, называемый функцией, объявляется при помощи (Bourne- и POSIX-диалекты) конструкций
name() compound-list
или (Korn-диалект)
function name compound-list
с использованием ключевого слова function, где compound-list — это составной список, например, if, case, for или while. Сформировать составной список из конвейера, простого или условного списка можно при помощи конструкций {list; } или (list), позволяющих выполнить list в том же или в отдельном дочернем процессе интерпретатора.
После объявления функция может быть неоднократно вызвана (как и любая другая внешняя или встроенная команда) с разными фактическими параметрами, значения которых в самой функции доступны при помощи подстановки позиционных параметров.
В примере из листинга ниже объявляется, а затем вызывается без параметров функция, выполняющая вывод идентификаторов пользовательских учетных записей, доступных в системе.
Список пользователей, зарегистрированных в операционной системе
bender@ubuntu:~$ function getusers↵
> {↵
> getent passwd | cut -f 1 -d : | xargs -n1 id↵
}↵
bender@ubuntu:~$ type -a getusers
getusers является функцией
getusers ()
{
getent passwd | cut -f 1 -d : | xargs -n1 id
}
bender@ubuntu:~$ getusers
uid=0(root) gld=0(root) группы=0(root)
uid=1001(finn) gid=1001(finn) группы=1007(candy), 1001(finn)
uid=1002(mike) gid=1002(mike) группы=1002(mike)
uid=1003(iceking) gld=1603(iceking) группы=1003(iceking)
uid=1004(marceline) gid=1004(marceline) группы=1004(marceline)
uid=1005(bubblegun) gid=1005(bubblegum) группы=1007(candy),1005(bubblegum)
uid=1006(fitz) gid=1008(fitz) группы=27(sudo),1008(fitz)
uid=1007(skillet) gid=1009(skillet) группы=1009(skillet)
uid=1008(bender) gid=1010(bender) группы=1010(bender)
В листинге ниже объявляется функция, являющаяся универсальным экстрактором «архивов». Сначала при помощи «красивой» формы [ команды test определяется наличие файла (-f), путевое имя которого будет передано первым фактическим параметром при вызове функции.
Затем, если заданный файл найден, при помощи множественного ветвления и шаблонов, «примеряемых» к имени заданного файла, определяется и выполняется в соответствующей ветви команда распаковки tar, gunzip, bunzip2, rar, unzip, uncompress или 7z. При запуске функции в режиме трассировки видно, как работает передача аргументов в функцию, как выполняются списки ветвления и множественного ветвления.
Универсальный экстрактор архивов
bender@ubuntu:~$ extract ()↵
> if [ -f $1 ] ↵
> then ↵
> case $1 шn ↵
> *.tar) tar xf $1;; ↵
> *.tar.bz2|*.tbz2) tar xjf $1;; ↵
> *.tar.gz|*.tgz) tar xzf $1;; ↵
> *.gz) gunzip $1;; ↵
> *.bz2) bunzip2 $1;;↵
> *.rar) rar x $1;; ↵
> *.zip) unzip $1;; ↵
> *.Z) uncompress $1;; ↵
> *.7z|*.iso) 7z X $1;• ↵
*) echo «Неизвестен распаковщик для return 1;; ↵
> esac ↵
> else ↵
£. > echo «‘$1’ не является файлом»; return 1 ↵
> fi
bender@ubuntu:~$ type -a extract
extract является функцией
extract ()
{
}
bender@ubuntu:~$ set -x
bender@ubuntu:~$ extract dvd.iso
+ extract dvd.iso
+ ‘[‘ -f dvd.iso ‘]’
+ case $1 in ,
+ 7z x dvd.iso
7Zip 9.20 Copyright (c) 1999-2010 Igor Pavlov 2010-11-18
p7zip Version 9.20 (locale=ru_RU.UTF-8,Utf 16=on,HugeFiles=on,4 CPUs)
Processing archive: dvd.iso
bender@ubuntu:~$ extract /tmp
+ extract /tmp
+'[‘ -f /tmp ’]’
+ echo “\’/tnp’\» не является файлом’
‘/tmp’ не является файлом
+ return 1
bender@ubuntu:~$ extract lynx_2.8.8dev.9-2ubuntu0e.12.04.1_all.deb
} + extract lynx_2.8.8dev.9-2ubuntu0.12.04.1_all.deb
+ ’[‘ -f lynx_2.8.8dev.9-2ubuntu0.12.04.l.all.deb ‘]’
+ case $1 in
* echo ‘Неизвестен распаковщик для ‘\»lynx_2.8.8dev.9.2ubuntu0.12.04.1_all.deb’\»‘
Неизвестен распаковщик для ‘lynx_2.8.8dev.9.2ubuntu0.12.04.1_all.deb’
+ return 1
Объявленные функции, как и переменные, располагаются в оперативной памяти процесса командного интерпретатора, в силу чего их время жизни и область видимости так же ограничиваются процессом их интерпретатора.
В этом смысле объявленные функции практически неотличимы от встроенных команд интерпретатора и могут расцениваться как его «расширения».
Сохранить объявленные функции и присвоенные переменные нельзя, но можно их повторно объявить и присвоить, воспользовавшись инициализационными dot-файлами интерпретатора, например сценариями .bashrc или .profile.