Использование команды Exec в сценарии Bash

Bash logo Scripts

При создании сценариев Bash мы можем захотеть перенаправить вывод всех операторов echo в файл журнала без явного указания оператора перенаправления и имени файла журнала после каждого оператора echo. Команда Bash exec - это мощная встроенная утилита, которую можно использовать для этой цели. В этом руководстве мы рассмотрим, как можно использовать команду exec для добавления протоколирования ошибок и вывода в сценарии оболочки. Мы также рассмотрим другие способы использования этой команды в сценариях командного интерпретатора.

Основы

При выполнении любой команды в оболочке Bash по умолчанию создается подоболочка, и порождается новый дочерний процесс (forked) для выполнения команды. Однако при использовании команды exec команда, следующая за exec, заменяет текущую оболочку. Это означает, что под-оболочка не создается, а текущий процесс заменяется этой новой командой.

Давайте проведем эксперимент, чтобы лучше понять это:

Мы проверили PID текущей оболочки с помощью команд echo $$ и pstree, а затем выполнили sleep на 300 секунд с помощью exec. Давайте теперь переключимся на другой терминал, чтобы проверить список процессов:

Как мы видим, PID 79, который изначально был назначен на Bash, теперь назначен на команду sleep.

Мы также наблюдаем, что после завершения 300-секундного сна сессия (терминал), имевшая PID 79, вышла, поскольку оболочка была заменена командой exec, и ее выполнение завершилось.

Замена процесса с помощью команды exec

Замена существующего процесса другой командой может быть мощным инструментом. Давайте рассмотрим эту идею на других примерах.

Профиль входа пользователя

Предположим, что Bash не является оболочкой по умолчанию на нашем Linux. Интересно, что с помощью команды exec мы можем заменить оболочку по умолчанию в памяти на оболочку Bash, добавив ее в профиль входа пользователя:

Бывают сценарии, когда мы хотим добавить определенную программу или меню в профиль входа пользователя (.bashrc или .bash_profile), и в таких случаях мы можем предотвратить доступ пользователя к интерпретатору Bash после завершения программы независимо от статуса завершения:

Вызовы программ внутри сценариев

Мы можем вызывать скрипты или другие программы внутри скрипта с помощью exec, чтобы перекрыть существующий процесс в памяти. Это экономит количество создаваемых процессов и, следовательно, системные ресурсы. Такая реализация особенно полезна в случаях, когда мы не хотим возвращаться в основной скрипт после выполнения подскрипта или программы:

В этом простом сценарии, управляемом пользовательским вводом, мы выполнили команду df и сценарий с помощью exec в различных пунктах меню.

Дескрипторы файлов и протоколирование в сценариях Shell с помощью команды exec

Команда exec - это мощный инструмент для манипулирования дескрипторами файлов (FD), создания вывода и протоколирования ошибок в сценариях с минимальными изменениями. В Linux по умолчанию файловым дескриптором:

  • 0 - является stdin (стандартный ввод)
  • 1 - stdout (стандартный вывод)
  • 2 - stderr (стандартная ошибка).

Ведение журнала в сценариях

Мы можем динамически открывать, закрывать и копировать stdout для выполнения операций протоколирования. Давайте перенаправим stdout (FD 1) в файл журнала:

Мы проверили, как мы можем записывать стандартный вывод в файлы, теперь давайте проверим, как мы можем также записывать стандартную ошибку в тот же файл:

Здесь мы скопировали stderr (2) в stdout (1), а stdout уже был изменен для записи в файл журнала.

Изменение Stdin для чтения из файла

Давайте создадим пример входного файла:

Пример файла

Теперь запустим пример для чтения из созданного нами файла:

И вот что мы получаем:

Пример вывода

Изменение файловых дескрипторов и восстановление значений по умолчанию

Мы также можем открывать и закрывать новые файловые дескрипторы для чтения и записи из файлов. Для демонстрации этого воспользуемся тем же входным файлом, что и в предыдущем разделе:

Здесь мы сначала открыли входной файл на FD 3, прочитали из файла и вывели его содержимое на терминал (по умолчанию на stdout). Наконец, мы использовали &- для закрытия FD 3. Когда этот сценарий выполняется, он выводит следующие данные:

вывод скрипта

Кроме того, скрипт создает выходной файл out.txt:

Вывод будет зарегистрирован в файле out.txt

cat out.txt
Обратите внимание, что вывод скрипта содержит только первый оператор echo. Интересно, что после первого оператора echo мы скопировали stdout на FD 4 и перенаправили его в другой файл. Позже, в последней строке, мы восстановили доступ к stdout, закрыв FD 4.

Запуск сценариев в чистой среде

Мы можем сбросить все переменные окружения для чистого запуска с помощью опции -c:

Так как команда printenv перечисляет переменные окружения, то при передаче ее в качестве аргумента команде exec здесь печатается пустой вывод.

Использование с командой Find

Опцию exec можно использовать для выполнения таких операций, как grep, cat, mv, cp, rm и многих других над файлами, найденными командой find. Давайте воспользуемся примером из нашей статьи о команде find, чтобы найти все файлы .java, содержащие слово "interface" в каталоге src:

Здесь мы указали опцию -type f, чтобы найти только обычные файлы. Затем мы использовали опцию -exec для выполнения команды grep в списке файлов, возвращенных командой find. Обратите внимание, что точка с запятой в конце заставляет команду grep выполняться для каждого файла по очереди, поскольку {} заменяется именем текущего файла. Обратите внимание, что обратная косая черта необходима для того, чтобы точка с запятой не интерпретировалась оболочкой.

Заключение

В этом руководстве мы рассмотрели различные варианты использования встроенной в Bash команды exec в сценариях оболочки.

Проще говоря, это мощный инструмент для замены процессов. В частности, ее использование с дескрипторами файлов в сценариях делает ее одним из самых мощных инструментов для гибкого протоколирования сценариев.

Avatar for Gnostis
Gnostis
Добавить комментарий