Intereting Posts
bash – ожидание и переменные Как этот каталог использует столько места Где разместить файлы приложений во встроенном Linux-развертывании? Удалить разрыв строки в файле tex Ошибка обновления Debian 7 (wheezy) до 8 (jessie), plymouth 0.9.0-9 полуконфигурирована Существуют ли расширенные разделы в таблице разделов GPT? Как добавить system_filter в конфигурацию одного файла Debian Exim? Реализация симметричной NAT с дополнительным портом источника? (программное обеспечение / ОС или аппаратный маршрутизатор) Изменить фона lightdm Проблема с gdm на debian Есть ли способ запустить процесс параллельно в цикле скрипта bash Ошибка «Неизвестный тип терминала» при попытке запустить emacsclient Как я могу передать Chromecast с помощью VLC? В каком каталоге хранятся сценарии, которые запускаются с новыми установками ядра? Может ли меньше использовать vim вместо vi по умолчанию, когда я нажимаю клавишу «v»?

Почему bashrc проверяет, является ли текущая оболочка интерактивной?

На моей установке 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 есть специальный случай для удаленных снарядов

После изучения проблемы я обнаружил, что удаленные оболочки обрабатываются по-разному. Хотя неинтерактивные оболочки 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 с болтливыми профилями оболочки на удаленной стороне? :

Например, это может произойти, если вы добавите это в свой профиль оболочки в удаленной системе:

эхо ""

Почему он просто висит? Это связано с тем, как scp в исходном режиме ожидает подтверждения первого сообщения протокола. Если он не двоичный 0, он ожидает, что это уведомление о удаленной проблеме и ждет, пока больше символов не сформирует сообщение об ошибке до тех пор, пока не появится новая строка. Поскольку вы не печатали еще одну новую строку после первой, ваш локальный scp просто остается в цикле, заблокирован при read(2) . Тем временем, после того, как профиль оболочки был обработан на удаленной стороне, запускался scp в режиме приемника, который также блокируется при read(2) , ожидая двоичного нуля, обозначающего начало передачи данных.

Заключение / TLDR

Большинство утверждений в типичном .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 более безопасна и делает вещи простыми.