Переменные окружения: 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=noninteractive | apt не задаёт вопросов |
http_proxy / https_proxy / no_proxy | прокси для curl, wget, apt |
Где задавать переменные надолго
| Файл | Кто его читает | Для чего |
|---|---|---|
/etc/environment | PAM при входе (login, ssh, su, cron) — не bash | общесистемные переменные; формат ИМЯ=значение, без export и без подстановок $VAR |
/etc/profile и /etc/profile.d/*.sh | login-оболочки 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'.