Настройка с использованием переменных среды

Настройка с использованием переменных среды #

Любые процессы, запущенные в операционной системе, поддерживают список переменных среды. Данный список передаётся новым процессам, которые будут запущены данным процессом.

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

Переменные в Bash #

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

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

variable=[value]

После такой конструкции для получения значения переменной можно будет обратиться с помощью синтаксиса ${variable}.

Для установки переменной окружения используется синтаксис:

export [envvar[=value]]...

Как можно увидеть из определения

  • за один вызов можно определить сразу несколько переменных окружения;
  • если не указано значение переменной, то будет использовано значение локальной переменной с этим именем.

Исследование переменных среды #

Для отображения переменных среды можно воспользоваться:

  • Встроенной командой Bash set. Одной из функций данной команды является вывод всех переменных, доступных на настоящий момент.
  • Приложением printenv. Приложение выводит значения указанных переменных окружений. Если не указать ничего, то будет выведен весь список переменных окружения.
  • Приложением env. Приложение позволяет запустить приложение в изменённом окружении. Если приложение не будет указано, то будет выведен список текущих переменных окружения.

Если выбирать инструмент по его изначальному предназначению, то логично выбрать printenv и посмотреть на его вывод. Следует учесть, что список достаточно большой, поэтому рекомендую перенаправить вывод данного приложения в пейджер less.

$ printenv | less

Примерный вывод приложения показан ниже:

LS_COLORS=
LANG=ru_RU.UTF-8
LESS=-MM
DISPLAY=:0
HOSTNAME=home-pc-alt
GPG_TTY=/dev/pts/4
USERNAME=root
USER=root
ENV=/root/.bashrc
INPUTRC=/etc/inputrc
PWD=/root
SSH_ASKPASS=/usr/lib/openssh/ssh-askpass
HOME=/root
TMP=/tmp/.private/root
XDG_DATA_DIRS=/root/.local/share/flatpak/exports/share:/var/lib/flatpak/exports/share:/usr/local/share:/usr/share
TMPDIR=/tmp/.private/root
SYSTEMD_PAGER=/usr/bin/less -FR
MAIL=/var/mail/root
LESSKEY=/etc/.less
SHELL=/bin/bash
TERM=alacritty
SHLVL=1
G_FILENAME_ENCODING=utf8
LOGNAME=root
XAUTHORITY=/root/.xauthXCDcR1
PATH=/root/bin:/sbin:/usr/sbin:/usr/local/sbin:/bin:/usr/bin:/usr/local/bin
G_BROKEN_FILENAMES=1
HISTSIZE=999
HISTFILESIZE=9999
LESSOPEN=|/usr/share/less/lesspipe.sh %s
_=/usr/bin/printenv

На каждой отдельной строке показаны пары: имя переменной среды и её значение после знака =. Например можно увидеть переменную USER, которая содержит значение root.

Для просмотра значения конкретной переменной необходимо передать её в качестве аргумента данному приложению.

# printenv HOME
/root

Встроенная команда set в отличие от printenv сортирует список переменных. Однако её вывод может содержать определения функций, что значительно увеличит вывод информации.

Также не стоит забывать, что простое обращение к переменной по значению позволит её получить и обработать:

$ echo $HOME
/home/andrey

Некоторые интересные переменные среды #

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

Переменная Содержимое
DISPLAY Номер графического сервера, на котором необходимо отображать окна приложений. В обычных пользовательских системах он будет равен :0, что соответствует первому номеру графического сервера.
EDITOR Название программы для редактирования текстовых файлов.
SHELL Название оболочки, которая занимается интерпретацией файлов.
HOME Путь к домашнему каталогу пользователя.
LANG Определение языка, правил сортировки и кодировки текущего языка.
OLDPWD Путь к предыдущему рабочему каталогу.
PAGER Название приложение для постраничного вывода информации. В современных дистрибутивах это обычно less
PATH Набор путей к каталогам, в которых командная оболочка выполняет поиск исполняемых файлов. Пути разделены между собой двоеточием.
PS1 Определение строки приглашения. Определяет содержимое приглашения, которое показывает оболочка.
PWD Путь к текущему рабочему каталогу.
TERM Идентификатор протокола взаимодействия с эмулятором терминала. Обеспечивает корректную передачу команд от оболочки эмулятору терминала, чтобы обеспечить корректное отображение информации.
USER Имя текущего пользователя.

Настройка переменных среды #

При запуске системы происходит настройка переменных среды для системы. Затем при входе конкретного пользователя Bash считывает загрузочные файлы сначала из системных каталогов, а затем из пользовательских каталогов.

Конкретный список файлов зависит от типа запуска командного интерпретатора. Существует всего 2 варианта.

  • Оболочка входа в систему. Под данной сессией подразумевается вариант входа в систему, когда у пользователя просят ввести имя пользователя и пароль. Это происходит при входе через виртуальный терминал, при подключении по SSH. Этот вход может происходить при авторизации через графический пользовательский интерфейс, но, к сожалению, не всегда.

    Терминал можно запустить в режиме оболочки, передав ему в качестве аргументов - или --login.

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

Следующие файлы применяются для настройки оболочки входа в систему.

Файл Содержимое
/etc/profile Глобальный конфигурационный файл, применяется ко всем пользователям.
/etc/profile.d Каталог с глобальными конфигурационными файлами, применяется файлом /etc/profile.
~/.bash_profile Конфигурационный файл пользователя. Обычно используется для изменения настроек, которые привносится глобальной настройкой
~/.bash_login Если предыдущий файл не был найден, то используется данный скриптовый файл
~/.profile Если 2 предыдущих файла не были найдены, то используется данный файл.
~/.xprofile Файл выполняется для настройки окружения при запуске при входе в графический пользовательский интерфейс, не является частью спецификации Bash

Следующие файлы применяются для настройки интерпретатора в обычном режиме.

Файл Содержимое
Переменная BASH_ENV Данная переменная окружения может содержать в себе путь к конфигурационному файлу. Он будет использован при обычном запуске. Обычно содержит путь к ~/.bashrc
~/.bashrc Персональный файл для настройки интерпретатора.
/etc/bashrc Глобальный конфигурационный файл, обычно считывается из пользовательского файла ~/.bashrc

Файл ~/.bashrc также считывается одним из файлов-профилей, таким образом окружение настраивается соответствующим образом.

Также стоит учитывать, что любой интерпретатор, как и любой другой процесс, наследуют настройки среды от своего процесса-родителя.

Содержимое загрузочных файлов #

Рассмотрим содержимое файла .bash_profile из ALT Linux 10 ветки.

# ~/.bash_profile
# The personal initialization file, executed for login shells.

# Source the aliases and functions.
if [ -f ~/.bashrc ]; then
        . ~/.bashrc
fi

# Define user specific environment and startup programs.

BASH_ENV=$HOME/.bashrc
export BASH_ENV

Этот файл написан на Bash, поэтому строки, начинающиеся с символа #, являются комментариями и не выполняются.

Первое осмысленное действие — это загрузка файла ~/.bashrc, если он существует. Для загрузки файла используется встроенная команда . или source. При использовании этой команды:

  • Указанный файл выполняется в рамках контекста текущего интерпретатора, новый интерпретатор не запускается.
  • Все изменения в состоянии интерпретатора, включая объявление функций, переменных и переменных окружения.

Данную форму легко спутать с запуском исполняемого файла: ./bashrc. Будьте внимательны относительно местоположения точки и наличия пробела.

Затем происходит настройка переменной окружения BASH_ENV. Она устанавливается равной в ~/.bashrc. Таким образом интерпретаторы, запущенные не в режиме входа в систему, будут использовать данный файл для настройки своего окружения.

Настройка переменной PATH #

Одной из ключевых задач, которые решают загрузочные файлы — настройка переменных окружения. Одной из важнейших переменных является переменная PATH, с помощью которой определяются каталоги для поиска исполняемых файлов.

Рассмотрим часть файла /etc/profile:

[ -n "$PATH" ] || PATH="/bin:/usr/bin:/usr/local/bin"
[ "$PATH" = "$HOME/bin" -o -z "${PATH##$HOME/bin:*}" -o \
  -z "${PATH%%*:$HOME/bin}" -o -z "${PATH##*:$HOME/bin:*}" ] ||
        PATH="$HOME/bin:$PATH"
export PATH

На первой строке проверяется: установлена ли переменная PATH. Если она не установлена, тогда в неё записываются стандартные пути:

  • /bin
  • /usr/bin
  • /usr/local/bin

Затем проверяется: есть ли в пути указание пути к каталогу bin в домашнем каталоге пользователя. Если нет, то к PATH в самое начало списка добавляется путь к нему. В Debian-подобных дистрибутивах базовые пути поиска находятся в обратном порядке, а каталог bin не добавляется в PATH.

В конце данной выдержки переменная PATH записывается как переменная среды для использования другими процессами.

Настройка среды #

После того как мы узнали где располагаются файлы по настройке переменных окружения и в каком порядке они вызываются, можно выполнить его настройку.

Если нам необходимо настроить переменные окружения нужным образом, то рекомендуется это делать в файлах конфигурации профиля, т.к. они считываются один раз при входе пользователя в систему и могут экспортировать свои настройки на все элементы системы. В случае ALT Linux таким конфигурационным файлом является ~/.bash_profile.

Настройку же деталей работы командного интерпретатора под нужды конкретного пользователя необходимо разместить в файле ~/.bashrc.

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

Перед тем как вносить изменения пожалуйста сохраните текущую конфигурацию, чтобы её можно было легко восстановить. Например можно создать копию файла .bashrc: cp .bashrc .bashrc.bak. В компьютерных классах университета все изменения в домашнем каталоге пользователя удаляются после перезагрузки компьютера. В случае работы в виртуальной машине вы можете воспользоваться механизмом создания снимков жёсткого диска, чтобы можно было восстановить файлы после случайного редактирования.

Задача. Интерактивное редактирование настроек Bash #

  1. Добавьте следующие строки в файл ~/.bashrc:
umask 0002
export HISTCONTROL=ignoredups
export HISTSIZE=1000
alias l.='ls -d .* --color=auto'
alias ll='ls -l --color=auto'
  1. Опишите назначение каждой из команд. Назначение переменных окружения можно найти в руководстве по Bash.
  2. Закройте текстовый редактор. Не закрывайте эмулятор терминала.
  3. Отобразите список переменных окружения. Сравните значение переменных окружения HISTCONTROL и HISTSIZE с теми значениями, что были добавлены в конфигурационный файл.
  4. Отобразите текущую маску по созданию файла. Сравните её значение с тем, что указано в конфигурационном файле.
  5. Отобразите текущий список псевдонимов. Сравните список по названиям псевдонимов и по их значению. Есть ли различия?
  6. Запустите новую сессию эмулятора терминала. Сравните значения переменных окружения, маску и псевдонима.
  7. В оригинальном терминале выполните загрузку настроек из файла ~/.bashrc с помощью команды source.
  8. Посмотрите на текущие значения переменных окружения, маски и псевдонимов.

Задача. Исследование поведения по умолчанию для файлов конфигурации Bash #

  1. Откройте файл ~/.bashrc. Данный файл использует содержимое другого файла для собственного наполнения. Где этот файл располагается?
  2. Откройте файл, используемый внутри ~/.bashrc.
    1. Какие другие файлы он использует для своей настройки?
    2. Кто может изменять содержимое данного файла?
  3. Рассмотрите каждый из следующих включённых файлов.
    1. Какую задачу они решают?
    2. В рамках какого пакета они были поставлены в систему?
  4. Какие требования предъявляются к последним файлам? Что следует сделать, чтобы добавленный файл был корректно включён в цепочку по настройке исполнения Bash?

Настройка приглашения Bash #

Рассмотрим одну из задач, которую можно решить с помощью редактирования файлов настройки, — настройка приглашения для командного интерфейса.

По умолчанию приглашение выглядит примерно следующим образом:

[me@linuxbox ~]$

Оно содержит в себе информацию об имени пользователя, названии компьютера, текущего рабочего каталога. Конкретное содержимое переменной окружения с названием PS1 (prompt string 1). Можно посмотреть содержимое данной переменной как и любой другой с помощью команды echo:

[me@linuxbox ~]$ echo $PS1
[\u@\h \W]\$

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

Рассмотрим краткую выжимку из управляющих последовательностей:

Последовательность Отображаемое значение
\a ASCII звонок. Требует от компьютера издать сигнал, если встречается в тексте.
\d Текущий день недели, месяц и день месяца. Например вт ноя 22.
\h Доменное имя текущего компьютера. Из имени убирается доменное имя.
\H Полное доменное имя компьютера.
\j Количество задач, которое запущено в текущем интерактивном терминале.
\l Название текущего устройства-терминала
\n Символ перевода на новую строку
\r Символ возвращения каретки к началу строки
\s Название приложения устройства-терминала
\t Текущее время в 24-часовом формате часы:минуты:секунды
\T Текущее время в 12-часовом формате
\@ Текущее время в 12-часовом формате с добавлением AP/PM
\A Текущее время в 24-часовом формате часы:минуты
\u Имя текущего пользователя
\v Номер версии командной оболочки
\V Номер версии и номер выпуска командной оболочки
\w Название текущего рабочего каталога
\W Последняя часть текущего рабочего каталога
\! Номер в истории текущей команды
\# Количество команд, которое было введено в рамках текущей сессии
\$ Показ уровня доступа. $ для обычных пользователей, # для суперпользователя
\[ Сигнализирует о начале последовательности непечатных символов. Обычно используется для манипулированием отображаемой информации: изменение цвета символов и передвижении курсора
\] Сигнализирует об окончании секции непечатных символов

Тестирование ряда приглашений #

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

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

[me@linuxbox ~]$ ps1_old="$PS1"

Для восстановления значения приглашения из переменной достаточно присвоить ей значение переменной ps1_old:

[me@linuxbox ~]$ PS1="$ps1_old"

Начнём наши эксперименты с присвоением пустого значения переменной PS1:

[me@linuxbox ~]$ PS1=

Если приглашению установить пустую строку приглашению, то пользователь ничего и не увидит. Приглашение, поле для ввода команды всё ещё присутствует, но пользователь не поймёт, что от него ожидают ввода очередной команды. Заменим пустоту минимальным приглашением:

PS1="\$ "

Такой вывод уже гораздо лучше. Пользователь видит, что от него ожидают ввода очередной команды.

Прошу обратить внимание на пробел, который стоит после знака доллара внутри двойных кавычек. Он необходим, т.к. визуально отделяет приглашение от команды, которую вводит пользователь.

Давайте разнообразим приглашение и добавим вызов гудка при показе приглашения:

$ PS1="\[\a\]\$ "

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

Обратите внимание, что непечатный символ был помещён между \[ и \]. Это связано с тем, что символ \a не продуцирует печатный символ, а Bash необходимо корректно определить размеры приглашения.

Добавим больше информации в приглашение: имя компьютера и информация о времени:

$ PS1="\A \h \$ "
17:33 linuxbox $

Показ времени в терминале может быть полезным, если мы хотим примерно отслеживать время выполнения определённых задач.

Ну и теперь соорудим приглашение, которое очень похоже на изначальное:

17:37 linuxbox $ PS1="<\u@\h \W>\$ "
<me@linuxbox ~>$

Добавление цвета в вывод терминала #

Большинство эмуляторов терминала способны выводить множество цветов, не только чёрный и белый. Помимо цвета поддерживаются также другие атрибуты шрифта: жирност, наклон. Также поддерживается возможность управления позицией курсора.

Цвет символов в терминале контролируется путём отправки эмулятору управляющих кодов, встроенных в поток символов, который необходимо отобразить пользователю. Управляющаяся последовательность не печатается на экране, а обрабатывается эмулятором терминала как инструкция для выполнения. В предыдущем разделе мы увидели, что последовательности управляющих кодов необходимо помещать внутри \[ и \].

Управляющие последовательности начинаются с восьмиричной цифры 033 (она соответствует нажатию на клавишу Escape), за которым идёт опциональный атрибут символа, за которым идёт инструкция. Например для установки нормального цвета текста (нулевой атрибут), используется следующая последовательность:

\033[0;30m

Ниже представлена таблица с поддерживаемыми цветами. Обратите внимание, что цвета поделены на 2 группы. Они отличаются номером аттрибута символа. 1 используется для указания жирного текста.

Последовательность Цвет текста Последовательность Цвет текста
\033[0;30m Black \033[1;30m Dark gray
\033[0;31m Red \033[1;31m Light red
\033[0;32m Green \033[1;32m Light green
\033[0;33m Brown \033[1;33m Yellow
\033[0;34m Blue \033[1;34m Light blue
\033[0;35m Purple \033[1;35m Light purple
\033[0;36m Cyan \033[1;36m Light cyan
\033[0;37m Light gray \033[1;37m White

Сделаем отображение приглашения красным цветом. Для этого необходимо изменить цвет отображения в начале:

<me@linuxbox ~>$ PS1="\[\033[0;31m\]<\u@\h \W>\$ "
<me@linuxbox ~>$

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

<me@linuxbox ~>$ PS1="\[\033[0;31m\]<\u@\h \W>\$\[\033[0m\] "
<me@linuxbox ~>$

Теперь только приглашение отображается красным цветом.

Помимо цвета текста можно также контролировать и цвет фона. Список управляющих последовательностей приведён в таблице ниже. Обратите внимание, что данные последовательности не поддерживают атрибут жирности

Последовательность Цвет текста Последовательность Цвет текста
\033[0;40m Black \033[0;44m Blue
\033[0;41m Red \033[0;45m Purple
\033[0;42m Green \033[0;46m Cyan
\033[0;43m Brown \033[0;47m Light gray

Мы сможем заменить красный текста на красный цвет фона в приглашении:

<me@linuxbox ~>$ PS1="\[\033[0;41m\]<\u@\h \W>\$\[\033[0m\] "
<me@linuxbox ~>$

Помимо нормального (0) и жирного (1) атрибутов символов поддерживаются ещё следующие:

  • 4 — подчёркивание;
  • 5 — мигающий;
  • 7 — инвертированный.

Однако многие эмуляторы терминала перестали поддерживать отображение мигающего текста.

Перемещение курсора #

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

Последовательность Действие
\033[l;cH Передвинуть курсор на линию l и колонку c
\033[nA Передвинуть курсор на n линий вверх
\033[nB Передвинуть курсор на n линий вниз
\033[nC Передвинуть курсор на n символов вперёд
\033[nD Передвинуть курсор на n символов назад
\033[2J Очистить экран и передвинуть курсор на позицию 0, 0
\033[K Очистить строку от текущего символа до конца линии
\033[s Сохранить текущее положение курсора
\033[u Восстановить положение курсора из сохранённого

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

PS1="\[\033[s\033[0;0H\033[0;41m\033[K\033[1;33m\t\033[0m\033[u\]
<\u@\h \W>\$ "

Для того, чтобы изменения сохранились между перезапусками эмулятора терминала, конфигурацию приглашения необходимо сохранить в настройки эмулятора, внутрь файла ~/.bashrc.

Задачи на контрольные последовательности #

  1. Сформируйте приглашение, которое выводит на первой строке информацию о пользователе, компьютере, а также полный путь к текущему рабочему каталогу. А на второй строке печатает текущее время, за которым следует символ > .
  2. Раскрасьте каждый элемент из приглашения выше в отдельный цвет.
  3. С помощью команды echo и управляющих последовательностей выведите на экран флаг России размером 12 символов в ширину и 9 символов в высоту.
  4. С помощью команды echo выведите пятиконечную красную звезду. Размер звезды не может быть меньше 12 символов в высоту.
  5. Разработайте скрипт, который проверяет наличие у него непустого первого аргумента. В случае запуска без данного аргумента скрипт должен выводить красное мигающее сообщение на стандартный поток вывода ошибок.

© A. M. Васильев, 2022, CC BY-SA 4.0, andrey@crafted.su