Почему запуск bash выполняется в режиме неинтерактивного ssh?

Вопрос или проблема

Я вижу необъяснимую разницу в поведении 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, что может повлиять на поведение оболочки.

  1. Linux (Debian):

    • Bash в Debian имеет включённую опцию SSH_SOURCE_BASHRC, что позволяет выполнять файлы ~/.bashrc даже в неинтерактивном режиме, если обнаружена переменная SSH_CLIENT.
    • Этот механизм обработан в исходном коде Bash, где при запуске через SSH проверяется наличие указанной переменной, и в случае её обнаружения происходит загрузка стандартного файла bashrc.
  2. FreeBSD:

    • В FreeBSD нет этой функциональности по умолчанию. Bash не будет выполнять ~/.bashrc или другие файлы конфигурации, если оболочка не является интерактивной или логинной, что и ожидает пользователь.
    • Таким образом, отсутствует инициализация переменных окружения для простых команд, выполненных через SSH без интерактивного входа.

Влияние на настройку переменных окружения

Такое различие в поведении создаёт ситуации, когда пользователю необходимо учитывать, какая ОС используется при работе с SSH. В случае, если проекты или приложения зависят от определённых переменных окружения, этот нюанс следует воспринимать как потенциальное источником проблем. Например, значение переменной MANWIDTH, выставленной для управления шириной справочных страниц, не будет установлено на FreeBSD, что может привести к неожиданному формату вывода при использовании команд, таких как man.

Заключение

Таким образом, различия в поведении Bash при подключении через SSH на Linux и FreeBSD объясняются наличием специфической функциональности в реализации Bash на Linux (в частности, в Debian) и её отсутствием в FreeBSD. Это различие подразумевает, что пользователям, работающим с выводом команд, следует внимательно следить за тем, какие переменные окружения могут или могут не инициализироваться в зависимости от операционной системы и конфигурации оболочки.

Оцените материал
Добавить комментарий

Капча загружается...