Шаблон подстановки команды
Внутри круглых скобок
>(command)
<(command)
Таким образом инициируется подстановка процессов. Здесь, для передачи результата работы процесса в круглых скобках, используются файлы /dev/fd/. [ 49 ] Имеет тот же эффект, что и именованные каналы (временный файл), фактически, именованные каналы некогда использовались в операциях подстановки процессов.
Между круглой скобкой и символом "<" или ">", не должно быть пробелов, в противном случае это вызовет сообщение об ошибке.
bash$ echo >(true)
/dev/fd/63
bash$ echo <(true)
/dev/fd/63
Bash создает канал с двумя файловыми дескрипторами, --fIn и fOut--. stdin команды true присоединяется к fOut (dup2(fOut, 0)), затем Bash передает /dev/fd/fIn в качестве аргумента команде echo. В системах, где отсутствуют файлы /dev/fd/, Bash может использовать временные файлы. (Спасибо S.C.)
cat <(ls -l)
# То же самое, что и ls -l | cat
sort -k 9 <(ls -l /bin) <(ls -l /usr/bin) <(ls -l /usr/X11R6/bin)
# Список файлов в трех основных каталогах 'bin', отсортированный по именам файлов.
# Обратите внимание: на вход 'sort' поданы три самостоятельные команды.
diff <(command1) <(command2) # Выдаст различия в выводе команд.
tar cf >(bzip2 -c > file.tar.bz2) $directory_name
# Вызовет "tar cf /dev/fd/?? $directory_name" и затем "bzip2 -c > file.tar.bz2".
#
# Из-за особенностей, присущих некоторым системам, связанным с /dev/fd/,
# канал между командами не обязательно должен быть именованным.
#
# Это можно сделать и так.
#
bzip2 -c < pipe > file.tar.bz2&
tar cf pipe $directory_name
rm pipe
# или
exec 3>&1
tar cf /dev/fd/4 $directory_name 4>&1 >&3 3>&- | bzip2 -c > file.tar.bz2 3>&-
exec 3>&-
# Спасибо S.C.
Ниже приводится еще один очень интересный пример использования подстановки процессов.
# Фрагмент сценария из дистрибутива SuSE:
while read des what mask iface; do
# Некоторые команды ...
done < <(route -n)
# Чтобы проверить это, попробуем вставить команду, выполняющую какие либо действия.
while read des what mask iface; do
echo $des $what $mask $iface
done < <(route -n)
# Вывод на экран:
# Kernel IP routing table
# Destination Gateway Genmask Flags Metric Ref Use Iface
# 127.0.0.0 0.0.0.0 255.0.0.0 U 0 0 0 lo
# Как указывает S.C. -- более простой для понимания эквивалент:
route -n |
while read des what mask iface; do # Переменные берут значения с устройства вывода конвейера (канала).
echo $des $what $mask $iface
done # На экран выводится то же самое, что и выше.
# Однако, Ulrich Gayer отметил, что ...
#+ этот вариант запускает цикл while в подоболочке,
#+ и поэтому переменные не видны за пределами цикла, после закрытия канала.
Подобно "настоящим" языкам программирования, Bash тоже имеет функции, хотя и в несколько ограниченном варианте. Функция -- это подпрограмма, блок кода который реализует набор операций, своего рода "черный ящик", предназначенный для выполнения конкретной задачи. Функции могут использоваться везде, где имеются участки повторяющегося кода.
function function_name { command ... }
или
function_name () { command ... }
Вторая форма записи ближе к сердцу C-программистам (она же более переносимая).
Как и в языке C, скобка, открывающая тело функции, может помещаться на следующей строке.
function_name () { command ... }
Вызов функции осуществляется простым указанием ее имени в тексте сценария.
Пример 22-1. Простая функция
#!/bin/bash
funky ()
{
echo "Это обычная функция."
} # Функция должна быть объявлена раньше, чем ее можно будет использовать.
# Вызов функции.
funky
exit 0
Функция должна быть объявлена раньше, чем ее можно будет использовать. К сожалению, в Bash нет возможности "опережающего объявления" функции, как например в C.
f1
# Эта строка вызовет сообщение об ошибке, поскольку функция "f1" еще не определена.
declare -f f1 # Это не поможет.
f1 # По прежнему -- сообщение об ошибке.
# Однако...
f1 ()
{
echo "Вызов функции \"f2\" из функции \"f1\"."
f2
}
f2 ()
{
echo "Функция \"f2\"."
}
f1 # Функция "f2", фактически, не вызывается выше этой строки,
#+ хотя ссылка на нее встречается выше, до ее объявления.
# Это допускается.
# Спасибо S.C.
Допускается даже создание вложенных функций, хотя пользы от этого немного.
f1 ()
{
f2 () # вложенная
{
echo "Функция \"f2\", вложенная в \"f1\"."
}
}
f2 # Вызывает сообщение об ошибке.
# Даже "declare -f f2" не поможет.
echo
f1 # Ничего не происходит, простой вызов "f1", не означает автоматический вызов "f2".
f2 # Теперь все нормально, вызов "f2" не приводит к появлению ошибки,
#+ поскольку функция "f2" была определена в процессе вызова "f1".
Читать дальше