Используйте эти переменные командного процессора и пишите современные, простые и информативные сценарии.
Как правило, разработчики использую Bash для того, чтобы писать сценарии оболочки, ссылаясь при этом на другие программы, которые выступают в роли команд, и добавляя всторенные функции языка командной оболочки Bash. Вместе с тем, все пользователи Unix и Unix-подобных систем используют Bash для взаимодействия с операционной системой через терминальные программы с графическим интерфейсом. Сценарий оболочки, написанный на языке Bash, состоит из нескольких синтаксических элементов. В сценариях оболочки мы довольно часто используем такие синтаксические элементы, как параметры. В языке командной оболочки Bash параметр – это объект, который хранит некое значение. У Bash есть три типа параметров: переменные, позиционные параметры и специальные параметры.
У переменной есть хорошо читаемое имя и несколько атрибутов, которые устанавливаются через встроенное объявление. Некоторые переменные определяются на основе общесистемных переменных среды, заданных в операционной системе. Кроме того, несколько переменных оболочки определяет командный интерпретатор Bash. И плюс ко всему, мы можем создавать как глобальные, так и локальные переменные внутри сценариев оболочки. Это зависит от наших собственных требований к разработке.
Интерпретатор Bash предлагает несколько полезных вещей в процессе выполнения сценария, доступ к которым вы можете получить посредством переменных оболочки. В некоторых случаях мы можем повысить производительность сценария с помощью переменных оболочки, не прибегая к использованию внешних процессов. Здесь я расскажу вам о нескольких полезных переменных оболочки, которые вы можете использовать в Bash, а также приведу практические примеры.
Проверяем версию интерпретатора Bash с помощью BASH_VERSINFO
У большей части программ командной строки есть флаг --version, который выводит на экран сведения о версии. У интерпретатора Bash тоже есть такой параметр командной строки, поэтому его пользователи могут использовать этот флаг для того, чтобы проверить сведения о версии. Допустим, что вы хотите воспользоваться более новым синтаксисом Bash с учетом версии интерпретатора или отобразить на экране сообщение о несовместимости для более старых исполнений интерпретатора Bash.
Чаще всего переменная оболочки BASH_VERSION возвращает строку с полной версией, поэтому для начала нам нужно извлечь и основной номер версии, и дополнительный. Между тем, вы можете воспользоваться массивом BASH_VERSINFO (выпущен в Bash 2.0) для того, чтобы получить доступ ко всем частям строки с версией:
#!/bin/bash
if ((BASH_VERSINFO[0] < 5 ||
(BASH_VERSINFO[0] == 5 && BASH_VERSINFO[1] < 1) )); then
echo "This script requires Bash 5.1 or a higher version."
exit 1
fi
Если версия Bash, которую использует пользователь, меньше, чем 5.1, то фрагмент кода, приведенный выше, останавливает выполнение сценария. Если вам все-таки нужно вывести на экран версию интерпретатора Bash вместе с основным и дополнительным номерами, то вы можете воспользоваться BASH_VERSION вместо того, чтобы собирать отдельные части BASH_VERSINFO:
#!/bin/bash
echo "You are using Bash ${BASH_VERSION%.*}"
Фрагмент кода выше выводит на экран основной и дополнительный номера версии интерпретатора Bash, и делает он это с помощью функции расширения параметров.
Выводим время исполнения сценария с помощью SECONDS
Bash стал естественным решением для автоматизации всех Unix и Unix-подобных систем. Именно по этой причине большая часть разработчиков использует его для целей автоматизации с опорой на сценарии оболочки. В некоторых случаях выполнение сценариев оболочки может занимать довольно много времени. Например, вы можете создать сценарий оболочки, который будет отвечать за автоматизацию развертывания программного обеспечения, и выполнение этого сценария может занять несколько часов. Если на экране будет отображаться количество пройденного времени, то это в данном случае, без сомнения, повысит удобство использования сценария. К тому же, вам может понадобиться автоматически завершить затянувшийся без конца повторяющийся сценарий оболочки с помощью значения времени ожидания.
Переменная SECONDS помогает измерить время выполнения сценария и выбрать решение для случаев, описанных выше. Взгляните на сценарий ниже. Он выводит на экран время выполнения команды.
#!/bin/bash
function start_timer() {
SECONDS=0
}
function display_elapsed() {
echo "Task executed in $SECONDS seconds"
}
# ---- Task 1 ----
start_timer
sleep 2
display_elapsed
# --- Task 2 ---
start_timer
sleep 3
display_elapsed
Как правило, команда timeout используется для запуска команды с заранее заданным временем ожидания. Кроме того, вы можете использовать переменную SECONDS для запуска простого фрагмента сценария в течение заданного количества времени (времени ожидания), как, например, здесь:
#!/bin/bash
TIMEOUT=10
while (( TIMEOUT > SECONDS )); do
prog=$(bc <<< "scale=1; $SECONDS / $TIMEOUT * 100")
echo "Processing... ${prog}%"
sleep 2
done
echo "Stopped with ${TIMEOUT}-second timeout."
Фрагмент кода, представленный выше, отлично подходит для неоднократного запуска простых задач в течение долгого времени. Эта настройка запускает двухсекундную задачу пять раз, учитывая при этом время ожидание в размере 10 секунд, и отображает на экране истекшее время выполнения в процентах:
(видео)
Реализация времени ожидания и процентного отображения истекшего времени выполнения в Bash, скриншот автора
Используем PWD и OLDPWD
Все пользователи Unix и Unix-подобных систем знают, что такое команды pwd и cd. Что, если вам нужно найти текущий или предыдущий рабочий каталог в Bash-сценарии? Как правило, эти команды запускаются через отдельные процессы (дочерние оболочки), в связи с чем, когда вы используете эти команды, они прекращают интерпретацию Bash-сценария для того, чтобы создать новый процесс. Для того, чтобы получить текущий и предыдущий рабочий каталоги, вы можете воспользоваться экспортируемыми переменными PWD и OLDPWD:
#!/bin/bash
cd /home
echo "PWD -> $PWD"
cd ~- # Go to the previous directory
echo "PWD -> $PWD"
echo "OLDPWD -> $OLDPWD" # OLDPWD -> /home
Эти переменные меняются, когда вы вводите команду cd. Как правило, они выступают в роли частичных значений, доступных только для чтения, с точки зрения присваивания переменных сценария. Например, если вы запустите следующую строку, это может привести к ошибке терминала, которая не исчезнет до тех пор, пока вы снова не введете команду cd:
PWD=/home
Команда выше меняет путь командной строки, но не исходного рабочего каталога:
(видео)
Изменение PWD приводит к некоторым проблемам, скриншот автора
Используем BASH_COMMAND совместно с Trap
BASH_COMMAND сохраняет значение текущей введенной команды. Если вы попытаетесь вывести сохраненное значение этой переменной с помощью команды echo, то увидите ту же команду echo, которую вы вводили до этого. Как же можно эффективно использовать эту переменную? И для какой проблемы предназначена BASH_COMMAND?
Вы можете использовать BASH_COMMAND в рамках ловушек (traps). Иными словами, с помощью команды trap вы можете получить самую последнюю команду (когда обработаете все ее ошибки). Здесь отличным примером может послужить отображение или обработка «неуспешной» команды с помощью команды trap. Взгляните на следующий фрагмент кода:
function __handle_cmd_err() {
exit_code=$?
echo "--------------"
echo "ERR: '$BASH_COMMAND' command was terminated with error code $exit_code"
}
trap __handle_cmd_err ERR
Если вы добавите этот фрагмент в свой файл ~/.bashrc, и команда завершит свою работу с кодом завершения, отличным от нуля, то вы увидите код завершения процесса и строку с «неуспешной» командой:
(видео)
Использование команды trap вместе с BASH_COMMAND, скриншот автора
Проследите за правильным использованием специального параметра $?. Если вы выводите на экран строку и тут же используете параметр $? в другом операторе echo, то вы получите код завершения оператора echo, а не тот, который вы ожидаете увидеть после неудачного завершения команды.
В примере выше BASH_COMMAND используется вместе с сигналом ERR. Но вы также можете использовать и сигнал INT для того, чтобы перехватывать прерывания клавиатуры и реализовывать операторы очистки.
Используем MACHTYPE, HOSTTYPE и OSTYPE в качестве альтернативы Uname и Arch
Системные администраторы и DevOps-инженеры довольно часто используют команду uname в своих сценариях оболочки для того, чтобы получить сведения о компьютере. Команда uname дает возможность получить сведения о ядре, центральном процессоре и операционной системе. Например, вы можете выполнить подстановку команды uname -m для того, чтобы присвоить Bash-переменной информацию о машинной архитектуре. Кроме того, с помощью команды arch вы можете вывести на экран системную архитектуру.
У Bash есть несколько переменных оболочки для получения сведений об операционной системе и аппаратном обеспечении. Вы можете использовать их для того, чтобы получить системную информацию, и вам не придется вызывать какие-либо внешние программы.
Вы можете выполнить проверки, воспользовавшись переменной оболочки OSTYPE для запуска кода, определяемого операционной системой, или путем определения названия операционной системы с помощью оператора case:
#!/bin/bash
OS="Unknown"
case "$OSTYPE" in
linux*)
OS="Linux" ;;
bsd*)
OS="BSD" ;;
# ---
# -- TODO: Add other OS type checks...
# ---
esac
echo $OS
HOSTTYPE возвращает сведения о системной архитектуре. MACHTYPE возвращает сведения о компьютерной системе, в том числе о системной архитектуре, типе компьютера и операционной системе. Эти переменные можно использовать для динамической генерации имен двоичных файлов, зависящих от платформы, в различных системах. Взгляните на следующий сценарий оболочки, который компилирует программу, написанную на С:
#!/bin/bash
gcc main.c -o myprogram-${OSTYPE%%-*}_${HOSTTYPE}
Сценарий, приведенный выше, генерирует myprogram-linux_x86_64 в системах GNU/Linux x64 и соответствующие имена двоичных файлов на других платформах.
Пожалуй, я закончу эту статью небольшим бонусным фактом о сценариях оболочки. Знаете ли вы, как проверить, является ли какая-то конкретная команда встроенной, псевдонимом или отдельным двоичным файлом?
Для этого вам нужна команда -a <command>:
(видео)
Проверка типов команд в терминале, скриншот автора