Почему экспорт переменной в оболочке ssh выводит список экспортируемых переменных?

17

Учти это:

$ ssh localhost bash -c 'export foo=bar'
terdon@localhost's password: 
declare -x DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/1000/bus"
declare -x HOME="/home/terdon"
declare -x LOGNAME="terdon"
declare -x MAIL="/var/spool/mail/terdon"
declare -x OLDPWD
declare -x PATH="/usr/bin:/bin:/usr/sbin:/sbin"
declare -x PWD="/home/terdon"
declare -x SHELL="/bin/bash"
declare -x SHLVL="2"
declare -x SSH_CLIENT="::1 55858 22"
declare -x SSH_CONNECTION="::1 55858 ::1 22"
declare -x USER="terdon"
declare -x XDG_RUNTIME_DIR="/run/user/1000"
declare -x XDG_SESSION_ID="c5"
declare -x _="/usr/bin/bash"

Почему экспорт переменной в bash -cсеансе, запущенном через ssh, приводит к этому списку declare -xкоманд (насколько я могу судить, список экспортируемых переменных в данный момент)?

Запуск того же самого без без bash -cэтого не делает:

$ ssh localhost  'export foo=bar'
terdon@localhost's password: 
$

И не произойдет, если мы не сделаем export:

$ ssh localhost bash -c 'foo=bar'
terdon@localhost's password: 
$ 

Я проверил это, выполнив sshing с одного компьютера с Ubuntu на другой (на обоих запущен bash 4.3.11) и на компьютере Arch, выполняя sshing себе, как показано выше (версия bash 4.4.5).

Что тут происходит? Почему экспорт переменной внутри bash -cвызова производит этот вывод?

Тердон
источник
Это не отвечает на вопрос, но результат является результатом выполнения export. Zsh делает то же самое.
Стивен Китт
@ StefhenKitt да, я знаю export, я пытаюсь понять, что происходит. Я отредактирую, чтобы уточнить, что это происходит только при экспорте.
Terdon
Ах, хорошо, я бы прочитал «список экспортируемых в настоящий момент переменных, насколько я могу судить» как означающее, что вы не знали, откуда вывод.
Стивен Китт
@ StefhenKitt Я имею в виду, я не уверен, что это каждая экспортируемая переменная или конкретное подмножество или что. Ой! Вы имеете в виду, что это результат exportзапуска в одиночку? Этого я не поняла.
Terdon
Обратите внимание, что foo=barне появляется в списке.
Дельтаб

Ответы:

31

Когда вы запускаете команду ssh, она вызывается $SHELLс -cфлагом:

-c    If the -c option is present, then commands are read from 
      the first non-option argument command_string.  If there  are
      arguments  after the command_string, the first argument is 
      assigned to $0 and any remaining arguments are assigned to
      the positional parameters.  

Итак, на ssh remote_host "bash -c foo"самом деле будет работать:

/bin/your_shell -c 'bash -c foo'

Теперь, так как команда, которую вы запускаете ( export foo=bar), содержит пробелы и не содержит правильных кавычек для формирования целого, команда exportпринимается за команду, которую нужно выполнить, а остальные сохраняются в массиве позиционных параметров. Это означает, что exportзапускается и foo=barпередается ему как $0. Окончательный результат такой же, как бег

/bin/your_shell -c 'bash -c export'

Правильная команда будет:

ssh remote_host "bash -c 'export foo=bar'"
xhienne
источник
9

ssh объединяет аргументы с пробелами и интерпретирует их как оболочка входа удаленного пользователя, поэтому:

ssh localhost bash -c 'export foo=bar'

ssh просит удаленную оболочку интерпретировать

bash -c export foo=bar

Команда (в действительности, если удаленный хост Unix-подобный, он будет работать с удаленной оболочкой с the-shell, -cа в bash -c export foo=barкачестве аргументов).

Большинство снарядов будет интерпретировать эту командную строку , как работает bashкоманда с bash, -c, exportи в foo=barкачестве аргументов (так работать , exportпока $0содержит foo=bar) , а вы хотите , чтобы запустить его с bash, -cи в export foo=barкачестве аргументов.

Для этого вам нужно использовать командную строку, например:

ssh localhost "bash -c 'export foo=bar'"

(или:

ssh localhost bash -c \'export foo=bar\'

для этого имеет значение) так что:

bash -c 'export foo=bar'

Командная строка передается в удаленную оболочку. Эта командная строка будет интерпретироваться большинством оболочек , как работает bashкоманда с bash, -cа в export foo=barкачестве аргументов. Обратите внимание, что с помощью

ssh localhost 'bash -c "export foo=bar"'

не будет работать, если оболочка входа удаленного пользователя была rcили, esнапример, "не является специальным оператором цитирования. Одиночные кавычки являются наиболее переносимыми операторами кавычек (хотя есть некоторые различия в том, как они интерпретируются между оболочками, см. Как выполнить произвольную простую команду над ssh, не зная оболочки входа удаленного пользователя? Для получения дополнительной информации).

Стефан Шазелас
источник