Поиск по сайту:

Основы автоматизации и сценариев Bash (часть 3)


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

Основы автоматизации и сценариев Bash

Если вы хотите начать с самого начала, прочитайте нашу статью «Автоматизация Bash и основы создания сценариев, часть 1». В этой заключительной статье из трех частей, посвященных автоматизации Bash и основам написания сценариев, запуск сценариев рассматривается как фоновый процесс.

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

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

Отладка скрипта

Отладка скрипта в Bash не должна быть сложной! Следите за веб-сайтом CloudSavvyIT, так как вскоре мы рассмотрим более полный инструмент отладки shellcheck для Bash, но на данный момент я хотел бы познакомить вас с отличным способом отладки сценариев Shell простым и понятным способом.

В оболочке Bash, которая, в конце концов, является «простым» двоичным файлом, работающим на вашем компьютере, а именно двоичным файлом bash, предусмотрена опция (-x), который, согласно man bash (выполнение этого в вашем терминале покажет руководство Bash), описывается как Команды печати и их аргументы по мере их выполнения, и это именно то, что он делает! Как это поможет при отладке? Взгляните на следующий пример:

#!/bin/bash

A=1
B=2
if [ "${AA}" == "1" -o "${B}" == "1" ]; then 
  echo "One ('1') was definitely stored in either the variable A, or the variable B"
  exit 0
else
  echo "Assert: could not locate the value '1' in the variables A and B"
  exit 1
fi

Здесь мы проверяем переменные A и B на соответствие значению 1. Идиома -o в операторе if означает OR, то есть либо первая часть (A, либо, скорее, AA здесь равно 1) истинно, или вторая часть (B равно 1) истинно и в в таком случае успех достигается.

Результатом работы скрипта будет запрограммированное утверждение, а программа завершится с кодом выхода 1, что обычно означает, что произошла какая-то ошибка. Если сценарий работал правильно, будет показано подтверждающее сообщение, и сценарий завершится с кодом выхода 0, что обычно означает, что все, что должен был сделать сценарий или утилита, было выполнено успешно.

Так почему же скрипт работает в утверждении? Возможно, вы уже заметили, что переменная A столкнулась с опечаткой в нашем операторе if, зарегистрированной в коде как AA: ошибка! Мы могли бы пойти и проверить сценарий, и если бы он был таким же коротким и простым, как показанный здесь сценарий, ошибка была бы быстро найдена. Но для программы на 5000 строк решение не такое простое, особенно если она использует несколько потоков, сложные подоболочки и т. д.

Теперь давайте отладим это с помощью параметра -x для Bash. Возможно, вы помните из второй части нашего курса по автоматизации и написанию сценариев в Bash, что подоболочка может быть инициирована с помощью встроенного набора идиом $ ( ... ) . Его также можно запустить, просто набрав bash или, в данном случае, bash -x внутри нашей верхней оболочки. В этом случае мы будем запускать скрипт внутри нашей подоболочки Bash с опцией -x, чтобы шаг за шагом наблюдать за тем, что происходит.

Таким образом, мы выполнили bash -x ./test_debugging.sh и заметили, что выполняется следующая условная проверка: [ == 1 -o 2 == 1 ]. Мы замечаем, что что-то не так: значение 2 сравнивается с 1 во второй части нашей условной проверки, а что происходит в первой части? Что-то сравнивается с 1, но это что-то… пустое (на что указывает пустая строка )!

Затем мы проверяем наш скрипт, почему это пустое место есть и почему оно не было заполнено значением нашей переменной A. Быстро понимаем ошибку AA вместо A, исправляем ошибку, и теперь скрипт работает нормально!

При использовании bash -x нужно помнить, что вы можете tee (прочитайте это как 'копировать') вывод Bash командой, перенаправляя stderr (вывод ошибки) на stdout (стандартный вывод) и захватывая его с помощью tee:

Здесь мы запускаем наш фиксированный скрипт и перенаправляем вывод ошибок (bash -x отправляет весь информативный вывод отладки в stderr, стандартный вывод ошибок, а не в stdout), используя 2 >&1 (который вместо этого перенаправляет наш вывод stderr на stdout — наш стандартный вывод). Затем мы захватываем стандартный вывод с помощью tee, и это сохраняет вывод в указанный файл, а именно bash_-x_output.txt.

Это позволяет разработчику Bash медленно просматривать в пошаговом формате свой написанный код. Особенно, когда программы становятся сложными, имеют функции, становятся многопоточными, запускают фоновые процессы и т. д., этот способ отладки может быть очень ценным. Например, я обычно использую bash -x примерно раз в две недели для отладки сложных скриптов.

Запуск скриптов как фоновых процессов

Запустить сценарий как фоновый процесс очень просто: просто добавьте & в конец имени сценария (с пробелом между ними). Мы определяем background.sh следующим образом:

#!/bin/bash

sleep 2

Затем мы запускаем его следующим образом — чтобы выделить тот факт, что он работает в фоновом режиме:

Здесь мы видим следующее: скрипт background.sh запускается в фоновом режиме (учитывая &, добавленное к имени скрипта через пробел), и немедленно командная строка вернется. Мы используем это здесь, указав следующую команду (sleep 1) непосредственно после фоновой идиомы &, которая также завершает эту команду единственной/единственной командой (другими словами, sleep 1 — совершенно новая команда).

Мы также завершаем нашу команду sleep 1 обычной идиомой end-of-command Bash, после чего мы выполняем echo, что sleep 1 завершен/сделан. Давайте теперь посмотрим, что происходит при выполнении этой строки.

Немедленно запускается наш фоновый процесс/скрипт (background.sh), который будет работать около 2 секунд. Визуально показан PID (идентификатор процесса) запущенного фонового процесса (а именно, 773183 для нашего первого ([1]) фонового процесса — и этот PID будет каждый раз отличаться время, когда вы запускаете фоновую программу/процесс), и наш sleep 1 (следующая инструкция для выполнения) теперь может быть выполнен, так как другая программа вернула наше приглашение (хотя это прямо не показано здесь, это то, что происходит, когда вы запускаете фоновый процесс; вы сразу же получаете обратно командную строку).

Начинается sleep 1 (при этом sleep 2 или, точнее, скрипт background.sh все еще работает в фоновом режиме, как отдельный процесс, в подоболочка запускается под этой оболочкой верхнего или более высокого уровня) и завершается через 1 секунду. После этого наш echo выполняется, показывая нам, что sleep 1 завершен. Через секунду наш процесс background.sh округляет 2-секундное ожидание и завершается.

Мы не видим, что он завершился, так как оболочка Bash ожидает некоторого взаимодействия, чтобы показать нам сообщения о состоянии. Таким образом, как только мы нажмем Enter, в любой момент после окончания двухсекундного сна мы увидим завершение фонового процесса в виде сообщения о состоянии [1]+ Done ./background.sh . Если вы вернетесь ко второй части нашей мини-серии, вы также можете увидеть, как мы могли бы использовать здесь wait для ожидания завершения/завершения PID фонового процесса. В нем также показано, сколько команд и утилит можно использовать в Bash комбинаторным образом.

Импорт скриптов с использованием источника

Импорт другого скрипта можно легко выполнить с помощью команды Bash source. Рассмотрим следующий скрипт testsource.sh:

#!/bin/bash

source mysource.sh

echo "${MYVAR}"

И соответствующий mysource.sh:

#!/bin/bash

MYVAR="Hello CloudSavvyIT Readers!"

Если мы просто сделаем исполняемым первый скрипт (testsource.sh) (используя chmod +x testsource.sh), но не второй скрипт (фактически мы отключим исполняемый флаг, чтобы четко показать, что это работает с использованием chmod -x в mysource.sh), второй скрипт по-прежнему вызывается успешно в результате source и выполняется как часть скрипта testsource.sh:

В скрипте mysource.sh мы устанавливаем для переменной MYVAR значение Привет, читатели CloudSavvyIT!. Затем этот сценарий извлекается из сценария testsource.sh с помощью инструкции source mysource.sh. Это приведет к тому, что mysource.sh будет выполнен в этот момент кода, и после завершения скрипт testsource.sh продолжит работу, несмотря на то, что все параметры, установленные в mysource.sh будет сохранен (подумайте об этом как о источнике из другого скрипта, чтобы легче было запомнить его действие).

В итоге

Мы рассмотрели отладку скриптов с помощью bash -x для отображения всех выполняемых команд. Мы также изучили, как запускать сценарий в качестве фонового процесса, и узнали, как мы можем импортировать сценарии, используя исходный код. Спасибо, что следите за обновлениями этой серии из 3 частей, из которых это была последняя статья!

Если вам интересно узнать больше о Bash, как насчет того, чтобы ознакомиться с нашими или статьями Primer: Циклы Bash: for, while и until, Условное тестирование в Bash: if, then, else, elif, а также Функции и локальные переменные Bash.