Группы команд и подоболочки
bash поддерживает возможность группировки команд. Воспользоваться ею можно двумя способами: либо путем группировки команд, либо путем применения подоболочки. Ниже приводятся примеры синтаксиса обоих подходов.
Группа команд:
{ команда1; команда2; [команда3; ...] }
Подоболочка:
(команда1; команда2; [команда3;...])
Группа команд заключается в фигурные скобки, а подоболочка оформляется круглыми скобками. Вот и вся разница. Однако обратите внимание, что из-за особенностей реализации группировки команд в bash фигурные скобки должны отделяться от команд пробелами и последняя команда должна завершаться точкой с запятой или символом перевода строки.
Перенаправление
Итак, где могут пригодиться группы команд и подоболочки? Даже при том, что между ними имеются важные различия (которые будут раскрыты далее), и те и другие используются в основном для перенаправления. Рассмотрим фрагмент сценария, выполняющий перенаправление вывода множества команд:
ls -l > output.txt
echo "Listing of foo.txt" >> output.txt
cat foo.txt >> output.txt
Выглядит достаточно просто: вывод трех команд перенаправляется в файл с именем output.txt. Воспользовавшись приемом группировки, то же самое можно выразить более кратко:
{ ls -l; echo "Listing of foo.txt"; cat foo.txt; } > output.txt
Подоболочка используется аналогично:
(ls -l; echo "Listing of foo.txt"; cat foo.txt) > output.txt
Этот прием помог нам сэкономить силы и время на вводе текста сценария, но истинная мощь групп команд и подоболочек проявляется в конвейерах. Создавая конвейеры из команд, мы часто сталкиваемся с необходимостью объединения результатов нескольких команд в общий поток. Группы команд и подоболочки упрощают эту задачу:
{ ls -l; echo "Listing of foo.txt"; cat foo.txt; } | lpr
Здесь мы объединили вывод трех команд и передали его по конвейеру на вход команды lpr, чтобы напечатать отчет.
Подстановка процессов
Несмотря на внешнее сходство и возможность объединения потоков для последующего перенаправления, между группами команд и подоболочками существуют важные отличия. Все команды, входящие в группу, выполняются в текущей оболочке, подоболочка (как можно догадаться из названия) выполняет свои команды в дочерней копии текущей командной оболочки. Это означает, что в момент запуска подоболочки создается копия текущей оболочки и передается новому экземпляру оболочки. Когда подоболочка завершается, ее копия окружения уничтожается, соответственно теряются любые изменения в окружении подоболочки (включая значения переменных).
Поэтому если нет прямой необходимости в использовании подоболочки, предпочтительнее использовать группы команд. Группы команд выполняются быстрее и требуют меньше памяти.
В главе 28 мы столкнулись с одной из проблем, характерных для подоболочек, когда выяснили, что команда read действует в конвейерах не так, как можно было бы ожидать. Там мы сконструировали следующий конвейер:
echo "foo" | read
echo $REPLY
после выполнения которого переменная REPLY всегда оставалась пустой, потому что команда read выполняется в подоболочке и ее копия REPLY уничтожается по ее завершении.
Так как конвейеры команд всегда выполняются в подоболочке, любые команды, присваивающие значения переменным, будут сталкиваться с этой проблемой. К счастью, командная оболочка поддерживает экзотическую форму подстановки, которая называется подстановкой процессов и может использоваться для преодоления указанных трудностей.
Подстановка процессов оформляется двумя способами: для процессов, отправляющих результаты в стандартный вывод:
<(список)
и для процессов, принимающих данные через стандартный ввод:
>(список)
где список — это список команд.
Ниже показано, как использовать подстановку процессов для решения проблемы с командой read:
read < <(echo "foo")
echo $REPLY
Подстановка процессов позволяет интерпретировать вывод подоболочки как обычный файл и осуществлять его перенаправление. Так как это форма подстановки, всегда можно узнать действительное подставляемое значение:
[me@linuxbox ~]$ echo <(echo "foo")
/dev/fd/63
Вывод результата подстановки командой echo показывает, что вывод подоболочки передается через файл с именем /dev/fd/63.
Подстановка процессов часто используется в циклах, содержащих команду read. Ниже приводится пример использования read в цикле, обрабатывающем список файлов в каталоге, созданном подоболочкой: