Использование команды Exec в сценариях оболочки
В этом руководстве подробно рассказывается о команде exec и ее использовании в сценариях оболочки.
Предпосылки:
Для выполнения действий, описанных в этом руководстве, вам потребуются следующие компоненты:
Функциональная система Linux. Узнайте больше о настройке виртуальной машины Ubuntu с помощью VirtualBox.
Доступ к пользователю без полномочий root с привилегией sudo.
Подходящий текстовый редактор. Например: Vim/NeoVim, Nano, Sublime Text, VSCodium и т. д.
Команда Exec
Команда exec сама по себе не является отдельным инструментом:
Скорее это внутренняя команда оболочки Bash:
Как следует из описания на странице руководства, если указана команда, exec заменяет ею оболочку, не порождая дополнительных процессов. Есть несколько доступных опций, которые изменяют поведение команды exec.
Основное использование
По умолчанию при каждом запуске команды Bash создает подоболочку и разветвляет команду.
Здесь команда echo выводит PID текущей оболочки. Оболочка Bash (PID: 978) порождает новый дочерний процесс для работы с командой sleep (PID: 8369).
А что, если мы запустим команду sleep с помощью exec?
Родительский процесс Bash заменяется командой sleep. При успешном выполнении он не возвращается в оболочку. Вместо этого сеанс завершается.
Чистая среда
Конфигурация Bash по умолчанию поставляется с множеством настроек и переменных среды. В определенном сценарии (например, при отладке) вы можете запустить свой скрипт/программу в чистой среде. С помощью exec мы можем запустить чистый экземпляр оболочки вместо текущего.
Во-первых, используйте команду printenv, чтобы вывести список всех переменных среды, которые настроены в данный момент:
Теперь используйте exec для запуска чистого экземпляра:
$ printenv
Запуск другой оболочки
Помимо Bash и «sh», существует множество других программ-оболочек, каждая из которых имеет свои уникальные возможности. Если программе/скрипту требуется определенная оболочка, вы можете использовать exec, чтобы заменить текущую оболочку Bash на желаемую.
В следующем примере мы заменяем Bash на «sh»:
$ exec sh
$ pstree -p
Использование Exec в сценариях
Изучив основы, теперь мы можем начать использовать exec в наших сценариях оболочки.
Пример 1. Работа с разными оболочками
Проверьте следующий скрипт:
echo $SHELL
echo "echo zsh launched successfully" > zsh.sh
exec zsh zsh.sh
Здесь первая команда echo выводит текущую оболочку. По умолчанию это должен быть Bash. Затем команда exec запускает «zsh», чтобы выполнить сценарий «zsh.sh».
Запустите следующий скрипт:
Пример 2. Переопределение существующего процесса
Всякий раз, когда вы вызываете команду/программу, Bash запускает новый процесс. В большинстве ситуаций это не вызывает беспокойства. Однако при работе с системой с очень ограниченными ресурсами (например, встроенное оборудование) может помочь использование exec для переопределения существующего процесса в памяти.
Проверьте следующий скрипт:
pstree -p
exec pstree -p
echo "hello world"
Здесь первая команда pstree показывает исходный макет дерева процессов. После выполнения команды exec вторая команда pstree заменяет запущенную оболочку. Команда echo в последней строке не выполнена.
Запустите следующий скрипт:
Поскольку это было частью скрипта, после успешного выполнения мы возвращаемся к исходной оболочке.
Поскольку команда exec заменяет родительскую оболочку другой командой/программой, любой последующий код становится недействительным. Будьте осторожны при использовании их в своих сценариях.
Пример 3. Ведение журнала
Оболочка Bash предлагает 3 уникальных файловых дескриптора для любой запущенной программы/скрипта:
STDOUT (1): стандартный вывод, сохраняет обычный вывод
STDERR (2): стандартная ошибка, сохраняет сообщения об ошибках
STDIN (0): стандартный ввод
Используя exec, мы можем перенаправить эти файловые дескрипторы в другое место, например, в файлы журналов. Это может помочь с отладкой и ведением журнала в целом.
Как правило, если вы хотите перенаправить STDOUT и STDERR в файл журнала, вы используете оператор перенаправления:
$ monke 2>&1 | tee test.log
Этот метод требует перенаправления в каждой точке, которую вы хотите зарегистрировать. Чтобы решить эту проблему, мы можем использовать команду exec для создания постоянного перенаправления для сеанса оболочки. Посмотрите следующий пример:
> test.log
exec 1>>test.log
exec 2>&1
echo "hello world"
wrong_command
Здесь первая строка создает пустой файл журнала. Первая команда exec устанавливает постоянное перенаправление STDOUT в файл журнала. Вторая команда exec перенаправляет STDERR на STDOUT.
При такой настройке все выходные данные и сообщения об ошибках сбрасываются в файл журнала:
$ cat test.log
Что делать, если сценарий создает непрерывные записи в журнале?
> test.log
exec 1>>test.log
exec 2>&1
while true
do
echo $RANDOM
sleep 5
done
Здесь, в первой части, мы создаем постоянное перенаправление STDOUT и STDERR в наш файл журнала. Бесконечный цикл while запускает команду echo до тех пор, пока мы не закроем ее принудительно с помощью «Ctrl + C». Переменная $RANDOM — это специальная переменная, которая возвращает случайную строку каждый раз, когда к ней обращаются.
Чтобы проверить запись журнала обновления, используйте следующую команду tail:
Обратите внимание, что это перенаправление действует только для сеанса оболочки.
Пример 4. Ввод из файла
Подобно тому, как мы создали постоянное перенаправление STDOUT и STDERR, мы также можем создать его для STDIN. Однако, поскольку для ввода используется STDIN, реализация немного отличается.
В следующем скрипте мы берем STDIN из файла:
echo "echo "hello world"" > input
exec < input
read line_1
eval $line_1
Здесь, в первой строке, мы используем эхо для генерации содержимого файла input_string с помощью перенаправления. Команда exec перенаправляет содержимое input_string в STDIN текущего сеанса оболочки. После чтения строки мы используем eval для обработки содержимого $line_1 как шелл-кода.
Запустите следующий скрипт:
Заключение
Мы обсуждали команду exec в Bash. Мы также продемонстрировали различные способы его использования в сценариях. Мы продемонстрировали использование exec для работы с несколькими оболочками, создания сценариев с эффективным использованием памяти и перенаправления файловых дескрипторов.
Это лишь малая часть того, чего можно добиться с помощью сценариев Bash. Узнайте больше о сценариях Bash из подкатегории «Программирование Bash».
Удачных вычислений!