Это вопрос, который я собирался опубликовать здесь несколько недель назад. Как и тердон , я понял, что 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
.