Это вопрос, который я собирался опубликовать здесь несколько недель назад. Как и тердон , я понял, что a создается .bashrcтолько для интерактивных оболочек Bash, поэтому не нужно .bashrcпроверять, работает ли он в интерактивной оболочке. Смущает то, что все дистрибутивы, которые я использую (Ubuntu, RHEL и Cygwin), имели некоторую проверку (тестирование $-или $PS1), чтобы убедиться, что текущая оболочка является интерактивной. Мне не нравится программирование грузового культа, поэтому я решил понять назначение этого кода в своем .bashrc.
Bash имеет специальный чехол для удаленных оболочек
Изучив проблему, я обнаружил, что удаленные оболочки обрабатываются по-разному. Хотя неинтерактивные оболочки Bash обычно не запускают ~/.bashrcкоманды при запуске, особый случай возникает, когда оболочка вызывается демоном удаленной оболочки :
Bash пытается определить, когда он запускается со своим стандартным входом, подключенным к сетевому соединению, как при выполнении, как правило rshd, демоном удаленной оболочки или демоном защищенной оболочки sshd. Если Bash определяет, что он выполняется таким образом, он читает и выполняет команды из ~ / .bashrc, если этот файл существует и доступен для чтения. Он не будет делать это, если вызывается как sh. Параметр --norcможет использоваться для запрета этого поведения, а --rcfileпараметр может использоваться для принудительного чтения другого файла, но ни при этом, rshdни в sshdобщем случае не вызывает оболочку с этими параметрами и не позволяет их указывать.
пример
Вставьте следующее в начале пульта .bashrc. (Если .bashrcиспользуется источник .profileили .bash_profile, временно отключите это во время тестирования):
echo bashrc
fun()
{
echo functions work
}
Выполните следующие команды локально:
$ ssh remote_host 'echo $- $0'
bashrc
hBc bash
- Нет
iв $-означает, что оболочка не является интерактивной .
- Не приводя
-в $0указывает , что оболочка не Войти оболочка .
Функции оболочки, определенные в пульте дистанционного управления, .bashrcтакже могут быть запущены:
$ ssh remote_host fun
bashrc
functions work
Я заметил , что ~/.bashrcэто только получен , когда команда задается в качестве аргумента для ssh. Это имеет смысл: когда sshиспользуется для запуска обычной оболочки входа .profileили .bash_profileзапуска (и .bashrcтолько из источника, если это явно сделано одним из этих файлов).
Основное преимущество, которое я вижу в .bashrcиспользовании удаленной команды (неинтерактивной), заключается в том, что можно запускать функции оболочки. Тем не менее, большинство команд в типичном случае .bashrcотносятся только к интерактивной оболочке, например, псевдонимы не раскрываются, если оболочка не является интерактивной.
Удаленная передача файлов может быть неудачной
Обычно это не проблема, когда rshили sshиспользуется для запуска интерактивной оболочки входа в систему или когда неинтерактивные оболочки используются для запуска команд. Тем не менее, это может быть проблемой для таких программ, как rcp, scpи sftpкоторые используют дистанционные оболочки для передачи данных.
Оказывается, оболочка по умолчанию для удаленного пользователя (например, Bash) неявно запускается при использовании scpкоманды. Там нет упоминания об этом на странице руководства - только упоминание, которое scpиспользуется sshдля передачи данных. Это приводит к тому, что если в нем .bashrcсодержатся какие-либо команды, которые печатаются в стандартный вывод, передача файлов завершится неудачно , например,
scp завершится с ошибкой без ошибок .
Смотрите также этот связанный отчет об ошибках Red Hat 15 лет назад, scp прерывается, когда в / etc / bashrc есть команда echo (которая в итоге была закрыта как WONTFIX).
Почему scpи sftpне удалось
SCP (защищенное копирование) и SFTP (защищенный протокол передачи файлов) имеют свои собственные протоколы для локального и удаленного конца для обмена информацией о передаваемых файлах. Любой неожиданный текст с удаленного конца (ошибочно) интерпретируется как часть протокола, и передача завершается неудачно. Согласно FAQ из Книги Улитки
Часто случается, однако, является то , что есть заявления в любой системе или для каждого пользователя файлов запуск оболочки на сервере ( .bashrc, .profile,
/etc/csh.cshrc, .loginи т.д.) , которые вывод текстовые сообщения на входе, предназначенные для чтения человека (например fortune, echo "Hi there!", и т.д.).
Такой код должен выводить только при интерактивных входах в систему, когда есть
ttyпривязка к стандартному вводу. Если он не выполнит этот тест, он вставит эти текстовые сообщения там, где они не принадлежат: в этом случае, загрязняя поток протокола между scp2/ sftpи sftp-server.
Причина, по которой файлы запуска оболочки актуальны, заключается в том, что sshd
при запуске любых программ от имени пользователя
используется оболочка пользователя (например, с помощью / bin / sh -c "command"). Это традиция Unix и имеет преимущества:
- Обычные настройки пользователя (псевдонимы команд, переменные среды, umask и т. Д.) Действуют при выполнении удаленных команд.
- Обычная практика установки оболочки учетной записи на / bin / false, чтобы отключить ее, не позволит владельцу запускать какие-либо команды, если по какой-либо причине аутентификация все же случайно пройдет успешно.
Детали протокола SCP
Для тех, кто интересуется подробностями того, как работает SCP, я нашел интересную информацию в разделе Как работает протокол SCP, который включает подробности о запуске scp с разговорчивыми профилями оболочки на удаленной стороне? :
Например, это может произойти, если вы добавите это в свой профиль оболочки в удаленной системе:
эхо ""
Почему просто висит? Это происходит из-за того, как scpв режиме источника ожидается подтверждение первого сообщения протокола. Если это не двоичный 0, он ожидает, что это уведомление об удаленной проблеме, и ждет, пока больше символов сформирует сообщение об ошибке, пока не прибудет новая строка. Так как вы не печатали еще одну новую строку после первой, ваша локальная система scpостается в цикле и заблокирована read(2). Между тем, после обработки профиля оболочки на удаленной стороне scpбыл запущен режим приемника, который также блокируется read(2), ожидая двоичного нуля, обозначающего начало передачи данных.
Заключение / TLDR
Большинство операторов в типичном .bashrcслучае полезны только для интерактивной оболочки, но не при выполнении удаленных команд с помощью rshили ssh. В большинстве таких ситуаций установка переменных оболочки, псевдонимов и определение функций нежелательна, а печать любого текста в стандартном формате активно вредна при передаче файлов с использованием таких программ, как scpили sftp. Выход из режима после проверки того, что текущая оболочка не является интерактивной, является наиболее безопасным для поведения .bashrc.