Если вы нашли эту страницу в поиске, то наверняка пытаетесь решить какую-то проблему с запуском bash.
Возможно, в вашем окружении bash не устанавливается переменная среды и вы не понимаете, почему. Возможно, вы засунули что-то в различные загрузочные файлы bash или в профили, или во все файлы наугад, пока это не сработало.
В любом случае, смысл этой заметки — как можно проще изложить процедуру запуска bash, чтобы вы могли справиться с проблемами.
Эта блок-схема обобщает все процессы при запуске bash.
Теперь подробнее рассмотрим каждую часть.
Сперва нужно выбрать, находитесь вы в командной оболочке входа (login shell) или нет.
Оболочка входа — это первая оболочка, в которую вы попадаете при входе в систему для интерактивного сеанса. Оболочка входа не требует ввода имени пользователя и пароля. Вы можете форсировать запуск оболочки входа, добавив флаг
Оболочка входа настраивает базовую среду при первом запуске оболочки bash.
Затем вы определяете, является оболочка интерактивной или нет.
Это можно проверить по наличию переменной
Или посмотреть, установлен ли параметр
Если в выдаче есть символ
Если вы находитесь в оболочке входа, то bash ищет файл
Затем ищет любой из этих трёх файлов в следующем порядке:
Когда находит один, то запускает его и пропускает другие.
Если вы находитесь в интерактивной оболочке без входа в систему (non-login shell), предполагается, что вы уже побывали в оболочке входа, окружение настроено и будет унаследовано.
В этом случае выполняются по порядку следующие два файла, если они существуют:
Если вы не находитесь ни в оболочке входа, ни в интерактивной оболочке, то ваше окружение действительно будет пустым. Это вызывает большую путаницу (см. ниже о заданиях cron).
В этом случае bash смотрит на переменную
У меня в 95% случаев отладка запуска bash связана с тем, что задание cron работает не так, как ожидалось.
Эта проклятая задача работает нормально, когда я запускаю её в командной строке, но фейлится при запуске в crontab.
Здесь две причины:
Обычно вы не замечаете или не заботитесь о том, что скрипт оболочки не является интерактивным, потому что среда наследуется от интерактивной оболочки. Это означает, что все
Вот почему зачастую приходится установить конкретный
Ещё одна распространенная проблема, когда скрипты по ошибке настроены на вызов друг друга. Например,
Обычно так происходит, когда кто-то пытался исправить какую-то ошибку и вроде бы всё заработало. К сожалению, когда нужно разделить эти разные типы сессий, то возникают новые проблемы.
Чтобы поэкспериментировать с запуском оболочки, я создал образ Docker, который можно использовать для отладки запуска оболочки в безопасной среде.
Запуск:
Dockerfile находится здесь.
Для принудительного логина и имитации оболочки входа:
Для проверки набора переменных
Для отладки
Возможно, в вашем окружении 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