Вопрос или проблема
Я вижу необъяснимую разницу в поведении ssh на Linux и FreeBSD, и именно поведение FreeBSD соответствует тому, чего я ожидал бы от простого языка man-страниц. То есть, что-то лишнее происходит на Linux, но я не знаю, что именно.
Я использую bash в качестве своей обычной оболочки входа на всех системах, как на Linux, так и на BSD. С помощью сложной многоуровневой настройки, включающей файлы запуска bash, я настраиваю свои переменные окружения для всех версиях bash, которые являются либо “входной”, либо “интерактивной” оболочкой, в техническом смысле, изложенном в начале man-страницы bash.
Теперь о различии: когда я ssh на сервер FreeBSD с командой, например ssh freebsd-host printenv
, эти переменные не устанавливаются. Что, после некоторых раздумий, является тем, что я должен ожидать, поскольку оболочка в этом случае не является ни входной, ни интерактивной. Но когда я ssh таким образом на хост Linux, переменные действительно устанавливаются — это явный признак того, что либо файл .bash_profile
, либо файл .bashrc
каким-то образом был обработан, несмотря на статус оболочки.
Мой вопрос, конечно, заключается в том, почему и как Linux может вести себя таким образом? Что заставляет запускать файлы запуска bash в этих обстоятельствах? Вся конфигурация sshd точно такая же и близка к дефолтным настройкам upstream, включая PermitUserEnvironment=no
. Все дистрибутивы Linux являются вариантами Debian, если это имеет значение.
Бонусный анекдот: я наткнулся на это, когда читал некоторые man-страницы с помощью ssh -t host man man
, и я не заметил ничего необычного на удаленном Linux, но на удаленном FreeBSD man-страница оказалась неправдоподобно узкой — потому что моего повсеместного задания MANWIDTH=100
там не было.
Разница в том, что Debian компилирует Bash с включенной функцией SSH_SOURCE_BASHRC
, в то время как FreeBSD, очевидно, этого не делает.
Версии Bash с этой включенной функцией дополнительно загружают ~/.bashrc (и системный bashrc) даже в том случае, если они не являются входными и не являются интерактивными, пока они находят переменную $SSH_CLIENT, установленную sshd (и обнаруживают, что они не работают под родительской оболочкой, которая бы это сделала).
shell.c-1132- /* сначала обработаем случай rshd/sshd. */
shell.c-1133- if (interactive_shell == 0 && no_rc == 0 && login_shell == 0 &&
shell.c-1134- act_like_sh == 0 && command_execution_string)
shell.c-1135- {
shell.c-1136-#ifdef SSH_SOURCE_BASHRC
shell.c:1137: run_by_ssh = (find_variable ("SSH_CLIENT") != (SHELL_VAR *)0) ||
shell.c-1138- (find_variable ("SSH2_CLIENT") != (SHELL_VAR *)0);
shell.c-1139-#else
shell.c:1140: run_by_ssh = 0;
shell.c-1141-#endif
shell.c-1142-#endif
shell.c-1143-
shell.c-1144- /* Если нас запустили через sshd или мы думаем, что нас запустили через rshd, выполняем
shell.c-1145- ~/.bashrc, если мы являемся верхнеуровневой оболочкой. */
shell.c-1146-#if 1 /* TAG:bash-5.3 */
shell.c:1147: if ((run_by_ssh || isnetconn (fileno (stdin))) && shell_level < 2)
shell.c-1148-#else
shell.c-1149- if (isnetconn (fileno (stdin) && shell_level < 2)
shell.c-1150-#endif
shell.c-1151- {
shell.c-1152-#ifdef SYS_BASHRC
shell.c-1153-# if defined (__OPENNT)
shell.c-1154- maybe_execute_file (_prefixInstallPath(SYS_BASHRC, NULL, 0), 1);
shell.c-1155-# else
shell.c-1156- maybe_execute_file (SYS_BASHRC, 1);
shell.c-1157-# endif
shell.c-1158-#endif
shell.c-1159- maybe_execute_file (bashrc_file, 1);
shell.c-1160- return;
shell.c-1161- }
Ответ или решение
Причины исполнения запуска Bash в условиях неинтерактивного SSH
При использовании SSH для подключения к удалённым машинам на различных операционных системах, таких как Linux и FreeBSD, можно столкнуться с разницей в поведении оболочки Bash, особенно в контексте настройки переменных окружения. Проблема, упомянутая пользователем, заключается в том, что при выполнении команд по типу ssh freebsd-host printenv
на FreeBSD переменные окружения не устанавливаются, в то время как на системах Linux (в частности, на Debian) они установлены. Давайте разберёмся, почему это происходит и какая причина за данной разницей.
Стартовые настройки Bash
Bash работает в различных режимах, включая "логин" и "интерактивный" режим. Каждый из них может запускать различные конфигурационные файлы для инициализации переменных окружения и настроек. В случае "логин" оболочки происходит загрузка файла ~/.bash_profile
, а в случае "интерактивной" — файла ~/.bashrc
. Однако при запуске из SSH, когда вы используете команду, как в данном случае, вы не получаете ни логин, ни интерактивную оболочку.
Отличия в реализации на Linux и FreeBSD
Причина, по которой на системах Linux переменные окружения устанавливаются даже в неинтерактивном режиме, кроется в дополнительно привнесённой функциональности, известной как SSH_SOURCE_BASHRC
. Эта особенность позволяет Bash проверять наличие переменной окружения SSH_CLIENT
. Если она установлена, межпроцессное взаимодействие предполагает, что Bash был запущен через SSH, что может повлиять на поведение оболочки.
-
Linux (Debian):
- Bash в Debian имеет включённую опцию
SSH_SOURCE_BASHRC
, что позволяет выполнять файлы~/.bashrc
даже в неинтерактивном режиме, если обнаружена переменнаяSSH_CLIENT
. - Этот механизм обработан в исходном коде Bash, где при запуске через SSH проверяется наличие указанной переменной, и в случае её обнаружения происходит загрузка стандартного файла
bashrc
.
- Bash в Debian имеет включённую опцию
-
FreeBSD:
- В FreeBSD нет этой функциональности по умолчанию. Bash не будет выполнять
~/.bashrc
или другие файлы конфигурации, если оболочка не является интерактивной или логинной, что и ожидает пользователь. - Таким образом, отсутствует инициализация переменных окружения для простых команд, выполненных через SSH без интерактивного входа.
- В FreeBSD нет этой функциональности по умолчанию. Bash не будет выполнять
Влияние на настройку переменных окружения
Такое различие в поведении создаёт ситуации, когда пользователю необходимо учитывать, какая ОС используется при работе с SSH. В случае, если проекты или приложения зависят от определённых переменных окружения, этот нюанс следует воспринимать как потенциальное источником проблем. Например, значение переменной MANWIDTH
, выставленной для управления шириной справочных страниц, не будет установлено на FreeBSD, что может привести к неожиданному формату вывода при использовании команд, таких как man
.
Заключение
Таким образом, различия в поведении Bash при подключении через SSH на Linux и FreeBSD объясняются наличием специфической функциональности в реализации Bash на Linux (в частности, в Debian) и её отсутствием в FreeBSD. Это различие подразумевает, что пользователям, работающим с выводом команд, следует внимательно следить за тем, какие переменные окружения могут или могут не инициализироваться в зависимости от операционной системы и конфигурации оболочки.