Блог студента

Как читать и определять переменные окружения и оболочки на Linux

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

Введение

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

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

Как работает окружение и его переменные

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

Окружение реализовано как строка, состоящая из пары ключ-значение. Если определяется несколько значений, то они последовательно разделены знаком двоеточия. Каждая пара будет выглядеть как:

KEY=value1:value2:...

Если значение содержит пробелы, тогда используют кавычки

KEY="value with spaces"

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

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

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

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

Вывод переменных оболочки и окружения

Каждая сессия оболочки хранит пути своих собственных переменных и переменных окружения. Их достигнуть можно разными способами.

Можно распечатать список всех переменных окружения используя env или printenv. По умолчанию они должны делать все то же самое:

printenv
XDG_GREETER_DATA_DIR=/var/lib/lightdm-data/rgt
USER=rgt
DESKTOP_SESSION=cinnamon
GNOME_TERMINAL_SCREEN=/org/gnome/Terminal/screen/782e62a7_614a_44c6_a444_cecbdf372225
DEFAULTS_PATH=/usr/share/gconf/cinnamon.default.path
QT_QPA_PLATFORMTHEME=qt5ct
PWD=/home/rgt
HOME=/home/rgt
SSH_AGENT_PID=1365
QT_ACCESSIBILITY=1
XDG_SESSION_TYPE=x11
XDG_DATA_DIRS=/usr/share/cinnamon:/usr/share/gnome:/home/rgt/.local/share/flatpak/exports/share:/var/lib/flatpak/exports/share:/usr/local/share:/usr/share
NVM_IOJS_ORG_MIRROR=https://iojs.org/dist
XDG_SESSION_DESKTOP=cinnamon
LC_ADDRESS=ru_RU.UTF-8
LC_NUMERIC=ru_RU.UTF-8
GTK_MODULES=gail:atk-bridge
PAPERSIZE=a4
TERM=xterm-256color
SHELL=/bin/bash
VTE_VERSION=5202
XDG_SEAT_PATH=/org/freedesktop/DisplayManager/Seat0
XDG_CURRENT_DESKTOP=X-Cinnamon
GPG_AGENT_INFO=/run/user/1000/gnupg/S.gpg-agent:0:1
GNOME_TERMINAL_SERVICE=:1.124
NVM_NODEJS_ORG_MIRROR=https://nodejs.org/dist
XDG_SEAT=seat0
SHLVL=1
LANGUAGE=en_US
LC_TELEPHONE=ru_RU.UTF-8
GDMSESSION=cinnamon
GNOME_DESKTOP_SESSION_ID=this-is-deprecated
LOGNAME=rgt
DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus
XDG_RUNTIME_DIR=/run/user/1000
XAUTHORITY=/home/rgt/.Xauthority
XDG_SESSION_PATH=/org/freedesktop/DisplayManager/Session0
XDG_CONFIG_DIRS=/etc/xdg/xdg-cinnamon:/etc/xdg
PATH=/home/rgt/.gems/bin:/home/rgt/.npm-global-modules/bin:/home/rgt/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/usr/lib/elixir/bin:/home/rgt/.racket/bin
LC_IDENTIFICATION=ru_RU.UTF-8
PS1=\$ 
SESSION_MANAGER=local/rgt-laptop:@/tmp/.ICE-unix/1301,unix/rgt-laptop:/tmp/.ICE-unix/1301
LESSOPEN=| /usr/bin/lesspipe %s
LC_TIME=en_US.UTF-8
_=/usr/bin/printenv

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

$ printenv SHELL
/bin/bash
$ printenv USER
rgt

С другой стороны env позволяет изменять окружение, указывая определение переменной. Например:

env VAR1="value VAR1" command_to_run command_option

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

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

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

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

$ set | head
BASH=/bin/bash
BASHOPTS=checkwinsize:cmdhist:complete_fullquote:expand_aliases:extglob:extquote:force_fignore:histappend:interactive_comments:progcomp:promptvars:sourcepath
BASH_ALIASES=()
BASH_ARGC=()
BASH_ARGV=()
BASH_CMDS=()
BASH_COMPLETION_VERSINFO=([0]="2" [1]="8")
BASH_LINENO=()
BASH_SOURCE=()
BASH_VERSINFO=([0]="4" [1]="4" [2]="19" [3]="1" [4]="release" [5]="x86_64-pc-linux-gnu")

Вывод этой команды довольно огромен. Для удобства работы с этими переменными можно использовать пейджеры more или less.

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

(set -o posix; set)

Возникнет список всех определенных переменных окружения и оболочки.

Можно попробовать сравнить этот вывод с выводом env или printenv команд, тем самым получив список только переменных оболочки. Возможно вывод будет довольно кривым:

comm -23 <(set -o posix; set | sort) <(env | sort)

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

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

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

Общие переменные окружения и консольной оболочки

Некоторые переменные окружения и оболочки очень полезны и к ним часто обращаются. Здесь перечислены общие переменные окружения, которые зачастую используются:

  • SHELL: отображает путь к оболочке, которая занимается интерпретацией тех или иных команд которые вводит пользователь. Как правило, по умолчанию, это будет интерпретатор bash, но возможно и применение других значений, которые можно указать.

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

  • USER: имя текущего пользователя оболочки.

  • PWD: переменная отображает значение текущей рабочей директории.

  • OLDPWD: предыдущая рабочая директория. Оболочка держит эту переменную для обратного переключения, когда запускается команда cd -.

  • LS_COLORS: определяет цвет кодов, которые используются для вывода команды ls. Чтобы различать типы файлов и директорий.

  • MAIL: отображает электронную почту текущего пользователя.

  • PATH: список директорий, которые будет проверять система, когда будет идти обращение к той или иной команде. Когда пользователь вводит команду, система смотрит указанные директории, в последовательном порядке.

  • LANG: текущий язык и локализационные настройки, включая кодировку символов.

  • HOME: текущая домашняя директория пользователя.

  • _: отображает вывод последней запущенной команды.

В дополнение к этим переменным окружения, имеются некоторые переменные оболочки, которые также будут часто встречаться:

  • BASHOPTS: список опций, которые используются при запуске bash. Это может быть полезно для выяснения, каким конкретно способом будет оперировать консольная оболочка.

  • BASH_VERSION: отображает конкретную версию bash.

  • BASH_VERSINFO: мажорная версия bash.

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

  • DIRSTACK: директории, которые доступны для команд pushd и popd.

  • HISTFILESIZE: количество линий, хранящиеся в файле истории набранных команд.

  • HISTSIZE: количество линий, которые можно хранить в памяти.

  • HOSTNAME: имя компьютера системы на данный момент.

  • IFS: внутренний разделитель поля в командной строке. По умолчанию это пробел.

  • PS1: строка приглашения на ввод. Эта переменная используется, для того, чтобы определить как будет выглядеть эта строка. Еще есть вторая строка PS2 которуя используется, когда команда многострочная.

  • SHELLOPTS: опции оболочки, которые можно определять с помощью команды set.

  • UID: идентификатор текущего пользователя.

Установка переменных окружения и оболочки

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

Создание переменной оболочки

Определение этой переменной будет происходить в пределах текущей сессии консольной оболочки.

$ TEST_VAR='Hello World!'

Кавычки здесь используются, поскольку значение переменной содержит пробел. В дальнейшем будет использоваться одинарные кавычки, поскольку основной момент в том, что особые знаки в bash будут правильно отображаться.

Опеределенная выше переменная теперь доступна в текущей сессии, но в дочернем процессе она будет отсутствовать. Увидеть ее можно применив команду grep на вывод set:

$ set | grep TEST_VAR
TEST_VAR='Hello World!'
$ bash                # создание новой дочерней сессии
$ set | grep TEST_VAR # делаем поиск переменной
$                     # вывод пуст

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

$ printenv | grep TEST_VAR
$ # вывод пуст

Чтобы получить значение той или иной переменной используется следующая конструкция:

$ echo $TEST_VAR
Hello World!

Команда echo делает вывод введенной строки как аргумента. Но в данном случае применяется знак $, в совокупности с ключом переменной, который возвращает ее значение.

Создание переменной окружения

Чтобы обернуть созданную переменную оболочки в переменную окружения, можно ее экспортировать:

$ export TEST_VAR
$ printenv | grep TEST_VAR
TEST_VAR=Hello World!

Если создать новую дочернюю сессию, то можно увидеть, что в ней также существует эта переменная:

$ bash
$ echo $TEST_VAR
Hello World!

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

$ export NEW_VAR="Testing export"
$ printenv | grep NEW_VAR
NEW_VAR="Testing export"
$ exit # делаем выход из текущего процесса и возвращаемся в родительский
$ echo $NEW_VAR
$ # ничего

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

Отвязка переменный

На данный момент переменная TEST_VAR находится в окружении. По необходимость можно делать отвязку переменных.

$ export -n TEST_VAR

Теперь если посмотреть в окружение, то удаленная переменная там будет отсутствовать.

$ printenv | grep TEST_VAR

Однако, она до сих пор существует в переменной оболочки:

$ set | grep TEST_VAR
TEST_VAR='Hello World!'

Если возникает потребность окончательно сделать отвязку переменной из оболочки и окружения, тогда можно применить команду unset:

$ unset TEST_VAR

Проверить результат команды можно с помощью echo:

$ echo $TEST_VAR

Отсутствует какое-либо возвращаемое значение, потому-что переменная была отвязана.

Установка переменных окружения по логину

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

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

Различие между логин, не-логин, интерактивной и не-интерактивной сессией оболочки

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

Логин сессия оболочки запускается по аутентификации пользователя. Если пользователь входит в сессию терминала или через SSH и аутентифицируется, когда это сессия оболочки будет определена как логин оболочка.

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

Помимо этих типов сессий существуют интерактивный и не-интерактивный. Первая прикрепляется к терминалу, вторая же наоборот.

Таким образом сессии оболочки могут различаться по этим двум типам.

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

В независимости от того, какая сессия определена как логин или не-логин, существуют некоторые заявления по которым происходит инициализация сессии оболочки.

Логин сессия когда стартует, будет читать конфигурационные заявления из файла /etc/profile в первую очередь. Затем уже будет смотреть в первом конфигурационном файле, пользовательской домашней директории, чтобы получить особые настройки пользователя.

Читаются исключительно файлы, которые распологаются в ~/.bash_profile, ~/.bash_login и ~/.profile.

В не-логин сессии оболочка читает файл /etc/bash.bashrc и затем пользовательский ~/.bashrc файл для построения своего окружения.

Не-интерактивные оболочки читают переменную окружения под названием BASH_ENV и читают указанный файл чтобы определить новое окружение.

Реализация переменных окружения

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

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

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

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

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

export VARNAME=value

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

$ source ~/.bashrc

Если необходимо установить системные переменные, то можно добавить их в /etc/profile, /etc/bash.bashrc или /etc/environment.

Заключение

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

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

Статья была переведена отсюда.

Мы учим программированию с нуля до стажировки и работы. Попробуйте наш бесплатный курс «Введение в программирование» или полные программы обучения по Node, PHP, Python и Java.

Хекслет

Подробнее о том, почему наше обучение работает →