При взаимодействии с вашим сервером в сеансе оболочки существует большое количество элементов информации, которые ваша оболочка использует для определения своего поведения и обеспечения доступа к ресурсам. Некоторые из этих настроек хранятся внутри настроек конфигурации, в то время как другие определяются с помощью пользовательского ввода.
Одним из способов, с помощью которого оболочка следит за всеми этими настройками и данными, состоит в использовании области, которая называется окружением. Окружение — это область, которую оболочка создает каждый раз при запуске сеанса, где содержатся переменные, определяющие свойства системы.
В этом руководстве мы обсудим вопрос взаимодействия с окружением и считывания или настройки переменных окружения и оболочки в интерактивном режиме и с помощью файлов конфигурации.
Каждый раз при запуске сеанса оболочки запускается процесс сбора и компиляции информации, которая должна быть доступной процессу оболочки и его дочерним процессам. Он получает данные для этих настроек из самых разнообразных файлов и настроек в системе.
Окружение предоставляет среду, через которую процесс оболочки может получать или задавать настройки и, в свою очередь, передавать эти настройки его дочерним процессам.
Окружение реализуется в виде строк, которые содержат пары ключ-значение. Если передается несколько значений, они обычно разделяются двоеточием (:
). Каждая пара, как правило, выглядит следующим образом:
KEY=value1:value2:...
Если значение содержит значительное количество пробелов, используются кавычки:
KEY="value with spaces"
Ключи в этих случаях являются переменными. Они могут относиться к одному из двух типов: переменные окружения или переменные оболочки.
Переменные окружения — это переменные, определяемые для текущей оболочки и наследуемые любыми дочерними оболочками или процессами. Переменные окружения используются для передачи информации процессам, которые запущены в оболочке.
Переменные оболочки — это переменные, содержащиеся исключительно в оболочке, внутри которой они были заданы или определены. Часто они используются для отслеживания кратковременных данных, например текущего рабочего каталога.
Согласно конвенции эти типы переменных обычно определяются с помощью заглавных букв. Это помогает пользователям различать переменные окружения внутри других контекстов.
Каждый сеанс оболочки отслеживает собственные переменные оболочки и окружения. Мы можем получить доступ к этим переменным разными способами.
Мы можем просмотреть список всех наших переменных окружения с помощью команд env
или printenv
. В состоянии по умолчанию они должны работать одинаково:
- printenv
OutputSHELL=/bin/bash
TERM=xterm
USER=demouser
LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:su=37;41:sg=30;43:ca:...
MAIL=/var/mail/demouser
PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games
PWD=/home/demouser
LANG=en_US.UTF-8
SHLVL=1
HOME=/home/demouser
LOGNAME=demouser
LESSOPEN=| /usr/bin/lesspipe %s
LESSCLOSE=/usr/bin/lesspipe %s %s
_=/usr/bin/printenv
Ниже представлен приблизительный стандартный вывод для обеих команд: printenv
и env
. Разница между двумя командами становится заметна только при использовании более специфического функционала. Например, с помощью printenv
вы можете запрашивать значения для отдельных переменных:
- printenv SHELL
Output/bin/bash
С другой стороны, env
позволяет изменять окружение, в котором запущены программы, с помощью передачи набора определений переменных в следующей команде:
- env VAR1="value" command_to_run command_options
Поскольку, как мы узнали ранее, дочерние процессы обычно наследуют переменные окружения родительского процесса, это дает вам возможность переопределить значения или добавить дополнительные переменные для дочернего процесса.
Как вы можете видеть в выводе команды printenv
, в системных файлах и процессах существует небольшое количество переменных окружения, доступных без нашего ввода.
Эти команды отображают переменные окружения, но как мы можем просмотреть переменные оболочки?
Для этого вы можете использовать команду set
. Если мы введем команду set
без каких-либо дополнительных параметров, то получим список всех переменных оболочки, переменных окружения, локальных переменных и функций оболочки:
- set
OutputBASH=/bin/bash
BASHOPTS=checkwinsize:cmdhist:expand_aliases:extglob:extquote:force_fignore:histappend:interactive_comments:login_shell:progcomp:promptvars:sourcepath
BASH_ALIASES=()
BASH_ARGC=()
BASH_ARGV=()
BASH_CMDS=()
. . .
Обычно это очень большой список. Вы, скорее всего, захотите преобразовать его в более компактный вид для удобства просмотра выводимых данных:
- set | 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, который обычно использует историю bash, если не воспользоваться экранированием или одинарными кавычками.
Теперь у нас есть переменная. Эта переменная доступна в нашем текущем сеансе, но она не будет передаваться дочерним процессам.
Мы можем увидеть это, выполнив с помощью команды grep поиск новой переменной в выводе set
:
- set | grep TEST_VAR
OutputTEST_VAR='Hello World!'
Мы можем убедиться, что это не переменная окружения, попробовав выполнить то же самое действие для команды printenv
:
- printenv | grep TEST_VAR
Вывод должен быть пустой.
Давайте воспользуемся этим как возможностью продемонстрировать способ получения доступа к значению любой переменной оболочки или окружения.
- echo $TEST_VAR
OutputHello World!
Как вы можете видеть, сослаться на значение переменной можно, добавив перед ее именем знак $
. Оболочка в результате понимает, что при обнаружении этой конструкции следует подставить значение переменной.
Теперь у нас есть переменная оболочки. Она не должна передаваться каким-либо дочерним процессам. Мы можем развернуть новую оболочку bash, используя для этого текущую оболочку, чтобы продемонстрировать это:
- bash
- echo $TEST_VAR
Если мы введем bash
, чтобы развернуть дочернюю оболочку, а затем попробуем получить доступ к содержимому переменной, значение не будет возвращено. Именно этого мы и ожидали.
Вернитесь к нашей оригинальной оболочке, введя exit
:
- exit
Теперь давайте превратим нашу переменную оболочки в переменную окружения. Мы можем сделать это с помощью экспорта переменной. Команда для выполнения этой задачи имеет соответствующее название:
- export TEST_VAR
Наша переменная будет превращена в переменную окружения. Мы можем убедиться в этом, снова проверив наш список переменных окружения:
- printenv | grep TEST_VAR
OutputTEST_VAR=Hello World!
В этот раз наша переменная отображается в списке. Давайте повторим наш эксперимент с дочерней оболочкой:
- bash
- echo $TEST_VAR
OutputHello World!
Отлично! Наша дочерняя оболочка получила переменную, настроенную в родительской оболочке. Перед тем как выйти из дочерней оболочки, давайте попробуем экспортировать другую переменную. Мы можем задать переменные окружения за один шаг, например:
- export NEW_VAR="Testing export"
Проверьте, что переменная успешно была экспортирована в окружение:
- printenv | grep NEW_VAR
OutputNEW_VAR=Testing export
Теперь давайте вернемся в нашу оригинальную оболочку:
- exit
Давайте посмотрим, доступна ли наша новая переменная:
- echo $NEW_VAR
Ничего не возвращается.
Это связано с тем, что переменные окружения передаются только дочерним процессам. Это не является встроенным способом настройки переменных окружения для родительской оболочки. Это хорошо в большинстве случаев, так как программы не могут влиять на операционное окружение, из которого они были вызваны.
Переменная NEW_VAR
была установлена в качестве переменной окружения в нашей дочерней оболочке. Эта переменная будет доступна из своей оболочки и любой из ее дочерних оболочек и процессов. Когда мы вышли обратно в нашу основную оболочку, это окружение было уничтожено.
Наша переменная TEST_VAR
все еще определена в качестве переменной окружения. Мы можем превратить ее обратно в переменную оболочки, введя следующую команду:
- export -n TEST_VAR
Она больше не является переменной окружения:
- printenv | grep TEST_VAR
Однако она все еще сохранила статус переменной оболочки:
- set | grep TEST_VAR
OutputTEST_VAR='Hello World!'
Если мы хотим полностью сбросить переменную, как оболочки, так и окружения, мы можем сделать это с помощью команды unset
:
- unset TEST_VAR
Мы можем убедиться, что эта переменная больше не задана:
- echo $TEST_VAR
Ничего не возвращается, потому что переменная была сброшена.
Мы уже упоминали, что многие программы используют переменные окружения для определения специфики своей работы. Мы не хотим задавать важные переменные каждый раз при запуске нового сеанса оболочки, и мы уже видели, сколько переменных уже задано при входе. Так как же мы можем создавать и определять переменные автоматически?
Это действительно более сложная проблема, чем это может показаться изначально, из-за множества файлов конфигурации, которые считывает оболочка bash в зависимости от того, как она запускается.
Оболочка bash считывает разные файлы конфигурации в зависимости от того, как запускается сеанс.
Одно из различий между сеансами заключается в том, что оболочка запускается в рамках сеанса входа или без входа.
Оболочка входа — это сеанс оболочки, начинающийся с аутентификации пользователя. Если вы выполняете вход в сеанс терминала или через SSH с аутентификацией, ваш сеанс оболочки будет настроен в виде оболочки со входом.
Если вы запускаете новый сеанс оболочки внутри аутентифицированного сеанса, как мы уже делали, вызывая команду bash
из терминала, запускается сеанс оболочки без входа. При запуске вашей дочерней оболочки вам не потребовалось вводить данные для аутентификации.
Еще одним отличием, которое можно отметить, является интерактивный или неинтерактивный характер сеанса оболочки.
Интерактивный сеанс оболочки — это сеанс оболочки, прикрепленный к терминалу. Неинтерактивный сеанс оболочки не прикреплен к сеансу терминала.
Таким образом, каждый сеанс оболочки классифицируется либо как сеанс входа или без входа, либо как интерактивный или неинтерактивный.
Обычный сеанс, который начинается с SSH, как правило, представляет собой интерактивный сеанс входа. Скрипт, запускаемый из командной строки, обычно запускается в неинтерактивном сеансе без входа. Сеанс терминала может быть иметь любое сочетание этих двух параметров.
То, относится ли сеанс оболочки к оболочке входа или без входа, определяет то, какие файлы будут считываться при инициализации сеанса оболочки.
Сеанс, запускаемый в виде сеанса входа, будет считывать данные конфигурации сначала из файла /etc/profile
. Затем он будет искать первый файл конфигурации сеанса входа в домашнем каталоге пользователя, чтобы получить данные конфигурации для конкретного пользователя.
Сеанс считывает первый из файлов ~/.bash_profile
, ~/.bash_login
и ~/.profile
, который ему удается найти, и не считывает остальные файлы.
В отличие от этого сеанс, определенный в оболочке без входа, будет читать файл /etc/bash.bashrc
и затем использовать файл ~/.bashrc
конкретного пользователя для создания окружения.
Неинтерактивные оболочки считывают значение переменной окружения BASH_ENV
и указанный в нем файл для определения нового окружения.
Как вы можете видеть, существует множество разных файлов, которые часто требуется просмотреть при определении наших настроек.
Эта возможность предоставляет большую гибкость, которая может быть полезна в определенных ситуациях, когда нам нужны определенные настройки при использовании оболочки входа и другие настройки для оболочки без входа. Однако большую часть времени мы будем использовать одни и те же настройки в обеих ситуациях.
К счастью, большинство дистрибутивов Linux позволяют настраивать файлы конфигурации входа для использования файлов конфигурации без входа. Это означает, что вы можете определить переменные окружения, которые вы хотите использовать в обоих случаях, только в файлах конфигурации без входа. Затем эти файлы будут считываться в обоих сценариях.
Чаще всего мы будем настраивать переменные окружения для конкретного пользователя, и наши настройки, как правило, будут доступны в оболочках как со входом, так и без входа. Это означает, что лучше всего использовать для определения этих переменных файл ~/.bashrc
.
Откройте этот файл:
- nano ~/.bashrc
Скорее всего, он уже содержит довольно большое количество данных. Большинство определений здесь предназначены для настройки опций bash, которые не имеют отношения к переменным окружения. Вы можете задать переменные окружения таким же образом, как вы делали это в командной строке:
- export VARNAME=value
Любые новые переменные окружения можно добавить в любое место файла ~/.bashrc
при условии, что они не помещаются внутри другой команды или цикла. Сохраните и закройте файл. В следующий раз при запуске сеанса оболочки ваше объявление переменной окружения будет считываться и передаваться в среду оболочки. Вы можете заставить ваш текущий сеанс считать файл прямо сейчас, введя следующую команду:
- source ~/.bashrc
Если вам потребуется задать общесистемные переменные, вы можете рассмотреть возможность их добавления в файлы /etc/profile
, /etc/bash.bashrc
или /etc/environment
.
Переменные окружения и оболочки всегда присутствуют в сеансах оболочки и могут быть очень полезны. Они представляют собой интересный способ настройки данных конфигурации родительского процесса для его дочерних процессов, а также позволяют задавать опции вне файлов.
Такой подход обладает множеством преимуществ в определенных ситуациях. Например, некоторые механизмы развертывания используют переменные окружения для настройки информации аутентификации. Это полезно, потому что данный способ позволяет избежать необходимости сохранения этих данных в файлах, которые могут быть видны третьим сторонам.
Существует много других, более простых, но очень распространенных сценариев, где вам может потребоваться считывать или изменять окружение вашей системы. Эти инструменты и техники могут послужить хорошей основой для внесения этих изменений и их корректного использования.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!