img

5 встроенных Bash-переменных, которые должен знать каждый разработчик

Используйте эти переменные командного процессора и пишите современные, простые и информативные сценарии.

Как правило, разработчики использую 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>:

(видео)

Проверка типов команд в терминале, скриншот автора

 

Ссылка
скопирована
Получите бесплатные уроки на наших курсах
Все курсы
Еще по теме:
img
Рассказываем, как скачать с гитхаб проект. Подробная инструкция со скриншотами
img
Рассказываем, что такое devtools, кто их придумал, зачем они нужны и какие задачи можно решить с помощью "инструментов разработчика"
img
В статье рассмотрим топ-20 библиотек, которые должны быть в арсенале каждого, кто занимается Data Science.
img
В этой статье обсудим один из важнейших аргументов функции, который ТЫ, мой друг, будешь использовать в каждом своем боте.
img
Настало время глубже погрузиться во взаимодействие человека с ботом. Сегодня изучим декоратор message_handler(). Узнаем, как боту реагировать на конкретные сообщения от пользователя и отвечать на его команды.