Если вы нашли эту страницу в поиске, то наверняка пытаетесь решить какую-то проблему с запуском bash.

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

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

Диаграмма


Эта блок-схема обобщает все процессы при запуске bash.



Теперь подробнее рассмотрим каждую часть.

Login Shell?


Сперва нужно выбрать, находитесь вы в командной оболочке входа (login shell) или нет.

Оболочка входа — это первая оболочка, в которую вы попадаете при входе в систему для интерактивного сеанса. Оболочка входа не требует ввода имени пользователя и пароля. Вы можете форсировать запуск оболочки входа, добавив флаг --login при вызове bash, например:

bash --login

Оболочка входа настраивает базовую среду при первом запуске оболочки bash.

Интерактивный?


Затем вы определяете, является оболочка интерактивной или нет.

Это можно проверить по наличию переменной PS1 (она устанавливает функцию ввода команд):

if [ "${PS1-}" ]; then
  echo interactive
else
  echo non-interactive
fi

Или посмотреть, установлен ли параметр -i, с помощью специальной переменной дефиса - в bash, например:

$ echo $-

Если в выдаче есть символ i, то оболочка является интерактивной.

В оболочке входа?


Если вы находитесь в оболочке входа, то bash ищет файл /etc/profile и запускает, если он существует.

Затем ищет любой из этих трёх файлов в следующем порядке:

~/.bash_profile
~/.bash_login
~/.profile

Когда находит один, то запускает его и пропускает другие.

В интерактивной оболочке?


Если вы находитесь в интерактивной оболочке без входа в систему (non-login shell), предполагается, что вы уже побывали в оболочке входа, окружение настроено и будет унаследовано.

В этом случае выполняются по порядку следующие два файла, если они существуют:

/etc/bash.bashrc
~/.bashrc

Ни один вариант?


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

В этом случае bash смотрит на переменную BASH_ENV вашей среды и выполняет соответствующий файл, который там указан.

Типичные трудности и эмпирические правила


Задания cron


У меня в 95% случаев отладка запуска bash связана с тем, что задание cron работает не так, как ожидалось.

Эта проклятая задача работает нормально, когда я запускаю её в командной строке, но фейлится при запуске в crontab.

Здесь две причины:

  • Задания cron не являются интерактивными.
  • В отличие от скриптов в командной строке, задания cron не наследуют среду оболочки.

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

Вот почему зачастую приходится установить конкретный PATH для задачи cron, как здесь:

* * * * * PATH=${PATH}:/path/to/my/program/folder myprogram

Скрипты, вызывающие друг друга


Ещё одна распространенная проблема, когда скрипты по ошибке настроены на вызов друг друга. Например, /etc/profile обращается к ~/.bashrc.

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

Образ Docker в песочнице


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

Запуск:

$ docker run -n bs -d imiell/bash_startup
$ docker exec -ti bs bash

Dockerfile находится здесь.

Для принудительного логина и имитации оболочки входа:

$ bash --login

Для проверки набора переменных BASH_ENV:

$ env | grep BASH_ENV

Для отладки crontab каждую минуту выполнятся простой скрипт (в /root/ascript):

$ crontab -l
$ cat /var/log/script.log

Комментарии (5)


  1. saipr
    18.05.2019 11:42

    Если вы нашли эту страницу в поиске, то наверняка пытаетесь решить какую-то проблему с запуском bash.

    Нет, проблем нет. А вы посмотрите на expect, вам может очень пригодиться.


  1. x67
    18.05.2019 12:21

    Статья выгляди слегка незаконченной


    1. dhaenoor
      19.05.2019 23:35

      Твоя магия сработала!


  1. Googolplex
    22.05.2019 01:37

    В оболочке fish, которой не надо было следовать легаси-интерфейсам, этот механизм первоначальной настройки шелла работает, имхо, гораздо логичнее и понятнее. В fish всегда, вне зависимости от того, login это шелл или interactive, читается один и тот же набор конфигов (~/.config/fish/config.fish, /etc/fish/config.fish, /usr/share/fish/config.fish). Если есть необходимость разделять конфигурацию шеллов, можно проверить тип оболочки с помощью команд status --is-login и status --is-interactive:


    if status --is-login
        for f in ~/config/fish/login.d/*.fish
            source $f
        end
    end
    
    for f in ~/config/fish/init.d/*.fish
        source $f
    end
    
    if status --is-interactive
        for f in ~/config/fish/interactive.d/*.fish
            source $f
        end
    end