На моей установке Arch, /etc/bash.bashrc
и /etc/skel/.bashrc
содержатся следующие строки:
# If not running interactively, don't do anything [[ $- != *i* ]] && return
В Debian /etc/bash.bashrc
имеет:
# If not running interactively, don't do anything [ -z "$PS1" ] && return
И /etc/skel/.bashrc
:
# If not running interactively, don't do anything case $- in *i*) ;; *) return;; esac
Однако, по словам man bash
, неинтерактивные оболочки даже не читают эти файлы:
When bash is started non-interactively, to run a shell script, for example, it looks for the variable BASH_ENV in the environment, expands its value if it appears there, and uses the expanded value as the name of a file to read and execute. Bash behaves as if the following com‐ mand were executed: if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi but the value of the PATH variable is not used to search for the file‐ name.
Если я правильно понимаю, файлы *.bashrc
будут считаны только в том случае, если BASH_ENV
установлен для указания на них. Это то, что не может произойти случайно и произойдет только в том случае, если кто-то явно установил переменную соответствующим образом.
Это, похоже, нарушает возможность того, что скрипты автоматически BASH_ENV
пользовательский .bashrc
, устанавливая BASH_ENV
, что может пригодиться. Учитывая, что bash никогда не будет читать эти файлы при запуске неинтерактивно, если явно не сказано об этом, почему файлы *bashrc
по умолчанию запрещают это?
Это вопрос, который я собираюсь опубликовать здесь несколько недель назад. Как и terdon , я понял, что .bashrc
доступен только для интерактивных оболочек Bash, поэтому нет необходимости в .bashrc
чтобы проверить, запущен ли он в интерактивной оболочке. Смутно, все дистрибутивы, которые я использую (Ubuntu, RHEL и Cygwin), имели некоторый тип проверки (тестирование $-
или $PS1
), чтобы обеспечить текущую оболочку интерактивной. Мне не нравится программирование культа груза, поэтому я решил понять цель этого кода в моем .bashrc
.
После изучения проблемы я обнаружил, что удаленные оболочки обрабатываются по-разному. Хотя неинтерактивные оболочки Bash обычно не запускают команды ~/.bashrc
при запуске, особый случай возникает, когда оболочка вызывается удаленным демонами оболочки :
Bash пытается определить, когда он запускается со стандартным входом, подключенным к сетевому соединению, как при выполнении удаленным
rshd
оболочки, обычноrshd
, или с помощьюsshd
защищенной оболочки. Если Bash определяет, что он выполняется таким образом, он считывает и выполняет команды из ~ / .bashrc, если этот файл существует и доступен для чтения. Это не будет сделано, если вызывается какsh
. Опция--norc
может использоваться для--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
не sftp
SCP (Secure copy) и SFTP (Secure File Transfer Protocol) имеют свои собственные протоколы для локальных и удаленных целей для обмена информацией о переносимом файле. Любой неожиданный текст с удаленного конца (ошибочно) интерпретируется как часть протокола, и передача не выполняется. Согласно часто задаваемому вопросу из книги улиток
Тем не менее, часто случается, что в файлах запуска системы или для каждого пользователя на сервере есть файлы (
.bashrc
,.profile
,/etc/csh.cshrc
,.login
и т. Д.),/etc/csh.cshrc
выводят текстовые сообщения на логин, предназначенный для чтения людьми (например,fortune
,echo "Hi there!"
и т. д.).Такой код должен производить только выходные данные в интерактивных входах, когда к стандартным
tty
подключенtty
. Если он не выполнит этот тест, он будет вставлять эти текстовые сообщения там, где они не принадлежат: в этом случае загрязнение потока протокола междуscp2
/scp2
иsftp-server
.Причина, по которой файлы запуска оболочки имеют отношение вообще, заключается в том, что
sshd
использует оболочку пользователя при запуске любых программ от имени пользователя (используя команду / bin / sh -c «command»). Это традиция Unix и имеет преимущества:
- Обычная настройка пользователя (псевдонимы команд, переменные среды, umask и т. Д.) Действуют, когда запускаются удаленные команды.
- Обычная практика установки оболочки учетной записи в / bin / false для ее отключения будет препятствовать тому, чтобы владелец выполнял какие-либо команды, если аутентификация по какой-то причине случайно не удалась.
Для тех, кто интересуется деталями работы SCP, я нашел интересную информацию о том, как работает протокол SCP, который включает в себя подробные сведения о запуске scp с болтливыми профилями оболочки на удаленной стороне? :
Например, это может произойти, если вы добавите это в свой профиль оболочки в удаленной системе:
эхо ""
Почему он просто висит? Это связано с тем, как
scp
в исходном режиме ожидает подтверждения первого сообщения протокола. Если он не двоичный 0, он ожидает, что это уведомление о удаленной проблеме и ждет, пока больше символов не сформирует сообщение об ошибке до тех пор, пока не появится новая строка. Поскольку вы не печатали еще одну новую строку после первой, ваш локальныйscp
просто остается в цикле, заблокирован приread(2)
. Тем временем, после того, как профиль оболочки был обработан на удаленной стороне, запускалсяscp
в режиме приемника, который также блокируется приread(2)
, ожидая двоичного нуля, обозначающего начало передачи данных.
Большинство утверждений в типичном .bashrc
полезны только для интерактивной оболочки – не при запуске удаленных команд с rsh
или ssh
. В большинстве ситуаций установка переменных оболочки, псевдонимов и определяющих функций нежелательна – и печать любого текста до стандартного извлечения активно вредна при передаче файлов с помощью таких программ, как scp
или sftp
. Выход из проверки того, что текущая оболочка не является интерактивной, является самым безопасным поведением для .bashrc
.
Страница руководства пренебрегает упоминанием того, что bash
также является источником .bashrc
для неинтерактивных удаленных оболочек, как в
ssh hostname command
http://git.savannah.gnu.org/cgit/bash.git/tree/shell.c#n1010
COMMAND EXECUTE BASHRC -------------------------------- bash -c foo NO bash foo NO foo NO rsh machine ls YES (for rsh, which calls 'bash -c') rsh machine foo YES (for shell started by rsh) NO (for foo!) echo ls | bash NO login NO bash YES
http://git.savannah.gnu.org/cgit/bash.git/tree/shell.c#n1050
/* If we were run by sshd or we think we were run by rshd, execute ~/.bashrc if we are a top-level shell. */ if ((run_by_ssh || isnetconn (fileno (stdin))) && shell_level < 2) { maybe_execute_file (SYS_BASHRC, 1); maybe_execute_file (bashrc_file, 1);
По соглашению, .bashrc
– это место, где пользователь сохраняет настройку конфигурации для оболочки.
Эти настройки конфигурации могут быть переменными среды, псевдонимами, фантастическими подсказками. С неинтерактивной оболочкой те, что не имеют смысла, не имеют смысла. Более того, неинтерактивная оболочка может быть вызвана во многих контекстах, вы не уверены, что эти переменные среды могут привести к ложному отрицательному случаю или даже к уязвимости безопасности.
Ближайшим примером является псевдоним типа:
alias cp='cp -i'
Затем он повесит вашу неинтерактивную оболочку навсегда.
Таким образом, проверка выполняется в верхней части .bashrc
чтобы гарантировать, что у нас не будет проблем.
Поскольку оболочку можно назвать неинтерактивной оболочкой входа , так что явное блокирование sourcing *bashrc
не имеет смысла.
Когда оболочка была вызвана как неинтерактивная оболочка входа , ее источник /etc/profile
, затем введите первый найденный в ~/.bash_profile
, ~/.bash_login
и ~/.profile
:
Когда bash вызывается как интерактивная оболочка входа или как неинтерактивная оболочка с параметром –login , она сначала считывает и выполняет команды из файла / etc / profile, если этот файл существует. После прочтения этого файла он ищет ~ / .bash_profile, ~ / .bash_login и ~ / .profile в этом порядке и считывает и выполняет команды из первого, который существует и доступен для чтения.
Ничто не мешает этим файлам искать источник .bashrc
, поэтому проверка внутри .bashrc
более безопасна и делает вещи простыми.