← Весь справочник

Переменные окружения: env, export, printenv

Окружение процесса — export, env -i и env VAR=…, printenv, где задавать переменные и какие файлы читает bash

Окружение — набор пар ИМЯ=значение, который каждый процесс получает от родителя при запуске. Через него программам передают настройки: PATH, HOME, LANG, EDITOR, адреса баз данных. Переменная оболочки попадает в окружение дочерних процессов, только если её экспортировали (export). env запускает команду с изменённым окружением, printenv печатает его. Важно: дочерний процесс получает копию окружения — изменить окружение родителя он не может.

Синтаксис

export ИМЯ=значение              # переменная оболочки + в окружение потомков
ИМЯ=значение команда             # переменная только для одной команды
env [-i] [-u ИМЯ] [ИМЯ=значение…] [команда [аргументы…]]
printenv [ИМЯ…]

Встроенные команды bash

КомандаЧто делает
export ИМЯ=значениезадать и экспортировать
export ИМЯэкспортировать уже существующую переменную
export -n ИМЯубрать из окружения, оставив переменной оболочки
export -pсписок экспортированных переменных в виде declare -x …
declare -x ИМЯ=значението же, что export
unset ИМЯудалить переменную полностью
ИМЯ=значение командазадать только для окружения этой команды
set -aэкспортировать все переменные, которые задаются после этого

Опции env

ОпцияЧто делает
без аргументовнапечатать окружение (как printenv)
ИМЯ=значение … командазапустить команду с добавленными или изменёнными переменными
-i, -начать с пустого окружения
-u ИМЯубрать переменную из окружения команды
-C каталогперейти в каталог перед запуском команды
-S 'строка'разбить строку на аргументы — для шебанга: #!/usr/bin/env -S python3 -u
-0при печати разделять переменные нулевым байтом
-vпоказать, что env делает на каждом шаге

Коды возврата env: 125 — ошибка самого env, 126 — команда найдена, но не запускается, 127 — команда не найдена, иначе — код команды.

printenv

ЗаписьЧто делает
printenvвсё окружение, по строке ИМЯ=значение
printenv HOME PATHтолько значения указанных переменных, по одному на строку
код возврата1, если хотя бы одной из переменных нет

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

Частые переменные

ПеременнаяЧто хранит
PATHкаталоги через :, где ищутся команды
HOME / USER / SHELLдомашний каталог / имя пользователя / оболочка входа
PWD / OLDPWDтекущий / предыдущий каталог
LANG, LC_*, LC_ALLлокаль: язык, кодировка, формат чисел и дат; LC_ALL перекрывает остальные
TZчасовой пояс: TZ=Europe/Moscow date
EDITOR / VISUAL / PAGERредактор и пейджер по умолчанию для crontab -e, git, man
TERMтип терминала
DEBIAN_FRONTEND=noninteractiveapt не задаёт вопросов
http_proxy / https_proxy / no_proxyпрокси для curl, wget, apt

Где задавать переменные надолго

ФайлКто его читаетДля чего
/etc/environmentPAM при входе (login, ssh, su, cron) — не bashобщесистемные переменные; формат ИМЯ=значение, без export и без подстановок $VAR
/etc/profile и /etc/profile.d/*.shlogin-оболочки bash и shобщесистемные настройки для входа; свои добавляй отдельным файлом в profile.d
~/.profile (или ~/.bash_profile)login-оболочка bash конкретного пользователяличные переменные, PATH; в Ubuntu ~/.profile подключает ~/.bashrc
/etc/bash.bashrc, ~/.bashrcинтерактивная не-login оболочка bash (новое окно терминала, bash внутри сессии)алиасы, приглашение, функции
$BASH_ENVнеинтерактивный bash (скрипты)файл, который выполняется перед скриптом

Какие файлы читаются:

Как запущен bashЧто читает
вход по ssh, su -, bash -l (login)/etc/profile → /etc/profile.d/*.sh → первый из ~/.bash_profile, ~/.bash_login, ~/.profile
новое окно терминала, bash (интерактивный)/etc/bash.bashrc → ~/.bashrc
скрипт, bash -c '…', cronничего, кроме файла из $BASH_ENV; окружение — только то, что передал родитель

Проверить, login ли текущая оболочка: shopt -q login_shell && echo login.

Примеры

# переменная только для одной команды
LANG=C sort file.txt
TZ=UTC date

# переменная оболочки не видна потомкам, пока её не экспортировать
APP_MODE=dev
bash -c 'echo "[$APP_MODE]"'      # []
export APP_MODE
bash -c 'echo "[$APP_MODE]"'      # [dev]

# запустить программу в чистом окружении — как её увидит cron или systemd
env -i PATH=/usr/bin:/bin bash -c 'env'

# убрать одну переменную для команды
env -u http_proxy curl -s http://localhost/

# проверить одну переменную; код 1, если её нет
printenv HOME
printenv NO_SUCH_VAR || echo "не задана"

# найти переменные по имени
env | grep -i proxy

# загрузить переменные из файла .env в окружение
printf 'DB_HOST=localhost\nDB_PORT=5432\n' > /tmp/app.env
set -a; source /tmp/app.env; set +a
printenv DB_HOST

# добавить каталог в PATH навсегда для всех login-оболочек
echo 'export PATH="$PATH:/opt/tools/bin"' > /etc/profile.d/tools.sh

# переносимый шебанг: найти интерпретатор через PATH
#!/usr/bin/env python3

Подводные камни

  • Скрипт не может изменить окружение вызвавшей оболочки. ./set-vars.sh с export X=1 внутри не задаст X в твоём терминале. Нужно выполнить файл в текущей оболочке: source set-vars.sh.
  • Без export переменная не попадает в программы. X=1 и потом python3 app.py — программа X не увидит. Проверяй через printenv X.
  • ~/.bashrc не читается скриптами и cron. И в Ubuntu он начинается с проверки «не интерактивная оболочка — выйти», поэтому даже bash -c его не подхватит. Переменные для скриптов задавай в самом скрипте или в crontab.
  • Строки в /etc/profile.d/ не действуют до нового входа. Уже открытые сессии их не увидят: перезайди или выполни source /etc/profile.d/файл.sh.
  • /etc/environment — не скрипт. export, $PATH и команды там не работают: файл читает PAM, а не bash. Значение PATH="$PATH:/x" запишется буквально.
  • sudo сбрасывает окружение. По умолчанию (env_reset) команда под sudo получает почти пустое окружение и свой PATH. Передать переменную: sudo VAR=значение команда или sudo -E.
  • env VAR=$X команда подставляет $X твоей оболочкой, до запуска env. Чтобы подстановку сделал дочерний процесс, бери команду в одинарные кавычки: env X=1 bash -c 'echo $X'.

См. также

variables · set · sudo · cron · su · which