Чому експорт змінної в оболонці 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: 
$ 

Я перевірив це, перенісши з однієї машини Ubuntu на іншу (обидва запущені bash 4.3.11) та на Arch-машині, sshing на себе, як показано вище (bash версія 4.4.5).

Що тут відбувається? Чому експорт змінної всередині bash -cвиклику дає такий результат?


Це не відповідає на питання, але результат є результатом запуску export. Зш робить те саме.
Стівен Кітт

@StephenKitt так, я знаю, що це export, я намагаюся зрозуміти, що відбувається. Я редагую, щоб уточнити, що це відбувається лише під час експорту.
terdon

Ну гаразд, я прочитав "список експортованих в даний час змінних, наскільки я можу сказати", це означає, що ви не знали, звідки надходить вихід.
Стівен Кітт

@StephenKitt Я маю на увазі, я не впевнений, що це кожна експортована змінна чи певна підмножина чи що. Ой! Ти маєш на увазі, що це результат 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'"

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, не знаючи оболонки входу віддаленого користувача? Для детальніше про це).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.