Окружение shell: переменные, PATH, dotfiles

TL;DR: Shell хранит два типа переменных: shell-переменные (локальные) и переменные окружения (наследуются дочерними процессами, export). PATH определяет где искать команды. Файлы инициализации: .bash_profile (login shell) и .bashrc (interactive non-login). Readline управляет редактированием строки (Ctrl+A/E/R/W).

Зачем это знать

  • command not found — обычно проблема с PATH
  • Переменная задана, но не видна в скрипте — не сделан export
  • Настройки не применяются — путаница между .bashrc и .bash_profile
  • Эффективная работа в терминале — горячие клавиши readline

Переменные оболочки vs переменные окружения

Переменная оболочки (shell variable)

Существует только в текущем экземпляре shell. Дочерние процессы её не видят.

MY_VAR="hello"
echo $MY_VAR          # hello
bash -c 'echo $MY_VAR'  # (пусто) — дочерний bash не видит

Переменная окружения (environment variable)

Передаётся всем дочерним процессам через механизм fork(). Создаётся через export.

export MY_VAR="hello"
bash -c 'echo $MY_VAR'  # hello — дочерний процесс видит
 
# Или в одну строку
export DB_HOST="localhost"

Направление только «вниз»: дочерний процесс получает копию окружения. Изменение переменной в дочернем процессе не влияет на родительский.

Временное окружение для одной команды

# Переменная существует только для этой команды
LANG=C sort file.txt
TZ=UTC date
DB_HOST=prod DB_PORT=5432 python app.py

Просмотр переменных

env                     # все переменные окружения
printenv HOME           # конкретная переменная окружения
echo $HOME              # значение (shell + env)
set                     # все переменные (shell + env + функции)
declare -p VAR          # тип и значение переменной

Стандартные переменные окружения

ПеременнаяНазначениеПример
PATHКаталоги поиска команд/usr/local/bin:/usr/bin:/bin
HOMEДомашняя директория/home/john
USERИмя текущего пользователяjohn
SHELLОболочка пользователя/bin/bash
PWDТекущая директория/home/john/project
OLDPWDПредыдущая директория (cd -)/tmp
LANG / LC_*Локаль (язык, кодировка)en_US.UTF-8
TERMТип терминалаxterm-256color
EDITORРедактор по умолчаниюvim
PAGERПрограмма для просмотра (less, more)less
PS1Формат приглашения (prompt)\u@\h:\w\$
HISTSIZEРазмер истории команд1000

PATH — поиск команд

Когда вы вводите команду (например ls), shell ищет исполняемый файл по каталогам, перечисленным в PATH, слева направо. Первое совпадение — выполняется.

echo $PATH
# /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
 
# Где именно находится команда
which python3           # /usr/bin/python3
type python3            # python3 is /usr/bin/python3
which -a python3        # все совпадения во всех каталогах PATH

Изменение PATH

# Добавить каталог в конец (текущая сессия)
export PATH="$PATH:/opt/myapp/bin"
 
# Добавить в начало (приоритет выше)
export PATH="/opt/myapp/bin:$PATH"
 
# Постоянно — добавить в ~/.bashrc или ~/.profile
echo 'export PATH="$PATH:$HOME/.local/bin"' >> ~/.bashrc

Почему «command not found»

  1. Программа не установлена → установить
  2. Программа установлена не в каталог из PATH → добавить каталог в PATH
  3. PATH перезаписан (потерян) → проверить dotfiles на ошибки
  4. Нет прав на исполнение → chmod +x
  5. Скрипт без ./ → shell не ищет в текущей директории (. обычно нет в PATH из соображений безопасности)

Dotfiles — файлы инициализации

Файлы инициализации bash

Bash выполняет разные файлы в зависимости от типа запуска:

                    ┌──────────────────┐
                    │  Login shell?    │
                    └────────┬─────────┘
                        ╱          ╲
                      Да            Нет
                      ↓              ↓
              /etc/profile      Interactive?
              ~/.bash_profile       ╱    ╲
              (~/.bash_login)     Да      Нет
              (~/.profile)        ↓       ↓
                              ~/.bashrc  BASH_ENV
                                         (если задан)
ФайлКогда читаетсяЧто в нём
/etc/profileLogin shell (все пользователи)Системные переменные, PATH
~/.bash_profileLogin shell (конкретный пользователь)Личные переменные, вызов .bashrc
~/.bashrcInteractive non-login shellАлиасы, функции, prompt, настройки
~/.profileLogin shell (если нет .bash_profile)Совместимость с sh

Login shell — при входе в систему (SSH, su -, login, TTY). Определяется по - в начале argv[0] или флагу --login.

Non-login interactive — открытие нового терминала в GUI, запуск bash из другого shell.

Типичный паттерн: .bash_profile делает source ~/.bashrc, чтобы настройки были доступны в обоих случаях.

# ~/.bash_profile (типичное содержимое)
# Загрузить .bashrc если есть
[ -f ~/.bashrc ] && source ~/.bashrc
 
# Переменные окружения (только для login)
export EDITOR=vim
export PATH="$PATH:$HOME/bin"
# ~/.bashrc (типичное содержимое)
# Алиасы
alias ll='ls -la'
alias gs='git status'
 
# Prompt
PS1='\[\e[32m\]\u@\h\[\e[0m\]:\[\e[34m\]\w\[\e[0m\]\$ '
 
# Функции
mkcd() { mkdir -p "$1" && cd "$1"; }

Glob и dotfiles

По умолчанию glob-паттерны (*, ?) не захватывают файлы, начинающиеся с точки:

ls *           # НЕ покажет .bashrc, .ssh/
ls .*          # только dotfiles
ls -a          # всё

Распространённые dotfiles

ФайлПрограмма
~/.bashrc, ~/.bash_profilebash
~/.ssh/config, ~/.ssh/authorized_keysSSH
~/.gitconfiggit
~/.vimrcvim
~/.config/XDG-совместимые приложения
~/.local/bin/Пользовательские скрипты (добавить в PATH)
~/.inputrcreadline (настройка ввода)

Readline: редактирование в командной строке

Библиотека readline используется bash (и многими другими программами) для обработки ввода. Горячие клавиши работают «из коробки».

Навигация

КлавишаДействие
Ctrl+AВ начало строки
Ctrl+EВ конец строки
Ctrl+F / Вперёд на символ
Ctrl+B / Назад на символ
Alt+FВперёд на слово
Alt+BНазад на слово

Редактирование

КлавишаДействие
Ctrl+UУдалить от курсора до начала строки
Ctrl+KУдалить от курсора до конца строки
Ctrl+WУдалить слово перед курсором
Alt+DУдалить слово после курсора
Ctrl+YВставить последнее удалённое (yank)
Ctrl+TПоменять местами два символа
Ctrl+LОчистить экран (как clear)

История

КлавишаДействие
Ctrl+RОбратный поиск по истории (начните вводить)
Ctrl+GОтмена поиска
Ctrl+P / Предыдущая команда
Ctrl+N / Следующая команда
!!Повторить последнюю команду
!$Последний аргумент предыдущей команды

Специальные символы shell

СимволНазначениеПример
*Любые символы (glob)ls *.log
?Один любой символls file?.txt
[abc]Один из символовls file[123].txt
{a,b}Перебор вариантов (brace expansion)cp file.{txt,bak}
~Домашняя директорияcd ~/projects
$Подстановка переменнойecho $HOME
$(...)Подстановка командыecho $(date)

Подробнее о кавычках и подстановках: shell-language.

Текстовые редакторы

nano — простой редактор

nano file.txt
# Ctrl+O — сохранить
# Ctrl+X — выход
# Ctrl+K — вырезать строку
# Ctrl+U — вставить
# Ctrl+W — поиск

vi/vim — мощный, но с порогом входа

vim file.txt
# Два основных режима:
#   Normal (по умолчанию) — навигация и команды
#   Insert (i/a/o)        — ввод текста
#   Esc                   — вернуться в Normal
 
# Normal: :w — сохранить, :q — выход, :wq — оба, :q! — выйти без сохранения
# Normal: dd — удалить строку, yy — копировать, p — вставить, u — undo
# Normal: /pattern — поиск, n — следующее совпадение

Получение помощи

man — страницы руководства

man ls                  # документация по ls
man 5 passwd            # секция 5 (формат файла), не команда passwd
man -k keyword          # поиск по описаниям (apropos)

Секции man:

СекцияСодержимоеПример
1Пользовательские командыman 1 passwd (команда)
2Системные вызовыman 2 open
3Библиотечные функцииman 3 printf
5Форматы файловman 5 passwd (формат /etc/passwd)
8Системное администрированиеman 8 mount

Другие источники

command --help          # краткая справка (большинство команд)
info command            # подробнее, чем man (иногда)
help builtin            # встроенные команды bash (cd, export, alias...)

Смена пароля и оболочки

passwd                  # сменить свой пароль
chsh -s /bin/zsh        # сменить оболочку (из /etc/shells)
chsh -l                 # список допустимых оболочек

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

СитуацияСовет
Переменная не видна в скриптеexport VAR — без export переменная не наследуется
Настройки из .bashrc не применяются при SSHSSH = login shell → читает .bash_profile. Добавить source ~/.bashrc в .bash_profile
PATH пуст/сломанexport PATH="/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin" — восстановить вручную
./script.sh работает, script.sh нет. (текущий каталог) не в PATH. Это нормально и безопасно
Alias не работает в скриптеАлиасы по умолчанию отключены в неинтерактивном режиме. Используйте функции

Связанные материалы