Почему удаленная команда SSH получает меньше переменных среды, чем при запуске вручную? [закрыто]

239

У меня есть команда, которая работает нормально, если я ssh к машине и запускаю ее, но не удается, когда я пытаюсь запустить ее с помощью удаленной команды ssh, например:

ssh user@IP <command>

Сравнение вывода «env» с использованием обоих методов приводит к различным средам. Когда я вручную захожу на компьютер и запускаю env, я получаю гораздо больше переменных окружения, чем при запуске:

ssh user@IP "env"

Есть идеи почему?

Том Файнер
источник
30
Почему именно этот вопрос закрыт как не по теме?
jottr
13
Возможно, потому что это не связано с программированием. Он должен был быть перемещен в Super User вместо закрытого.
Даниэль Х
8
bashне язык сценариев?
Дан Ниссенбаум
В Debian 8 по какой-то причине мне пришлось изменить оболочку на bash в / etc / passwd. Даже переконфигурировать тире, чтобы / bin / sh указывал на bash, не помогло.
user1050755

Ответы:

173

Существуют разные типы снарядов. Оболочка выполнения команд SSH - это неинтерактивная оболочка, тогда как обычная оболочка - это либо оболочка для входа, либо интерактивная оболочка. Описание следует из man bash:

       Оболочка входа - это тот, чей первый символ аргумента
       ноль - это -, или один начинается с опции --login.

       Интерактивная оболочка запускается без опций
       аргументы и без опции -c, чей стандартный ввод
       и ошибка оба связаны с терминалами (как определено
       по isatty (3)) или один из них начинается с опции -i. PS1 это
       set и $ - включает i, если bash интерактивен, что позволяет
       сценарий оболочки или файл запуска для проверки этого состояния.

       В следующих параграфах описано, как bash выполняет свои
       загрузочные файлы. Если какой-либо из файлов существует, но не может быть
       читай, bash сообщает об ошибке. Тильды раскрыты в файле
       имена, как описано ниже в разделе Расширение Тильды в
       РАЗДЕЛЕНИЕ.

       Когда bash вызывается как интерактивная оболочка входа или как
       неинтерактивная оболочка с параметром --login, сначала
       читает и выполняет команды из файла / etc / profile, если
       этот файл существует. После прочтения этого файла, он ищет
       ~ / .bash_profile, ~ / .bash_login и ~ / .profile, в этом
       порядок, а также читает и выполняет команды с первого
       что существует и читаемо. Опция --noprofile может
       использоваться, когда оболочка запущена, чтобы подавить это поведение
       IOR.

       При выходе из оболочки входа в систему bash читает и выполняет команды
       из файла ~ / .bash_logout, если он существует.

       Когда интерактивная оболочка, которая не является оболочкой входа
       запущен, bash читает и выполняет команды из ~ / .bashrc,
       если этот файл существует. Это может быть запрещено с помощью
       опция --norc. Опция --rcfile file заставит bash
       читать и выполнять команды из файла вместо
       ~ / .Bashrc.

       Когда bash запущен неинтерактивно, для запуска оболочки
       скрипт, например, он ищет переменную BASH_ENV в
       окружающая среда, расширяет свою ценность, если она там появляется,
       и использует расширенное значение в качестве имени файла для чтения
       и выполнить. Bash ведет себя так, как будто следующая команда
       были выполнены:
              if [-n "$ BASH_ENV"]; затем . "$ BASH_ENV"; фи
       но значение переменной PATH не используется для поиска
       для имени файла.

Винко Врсалович
источник
7
Отличный ответ, это была именно проблема, необходимые переменные окружения находились в / etc / bashrc, который не был получен в неинтерактивном режиме. Перемещение их в / etc / profile решило проблему. Большое спасибо!
Том Фейнер
1
Этот ответ только в частичном решении. Вот еще немного информации: добавьте другую переменную среды (например, export SOURCED_SYSTEM_ETC_BASHRC) в различные файлы, которые поступают: / etc / profile, etc / bashrc, ~ / .profile, ~ / .bash_profile, ~ / bashrc. Затем найдите эту уникальную переменную в выводе Jenkins. В моем случае я обновил / etc / bashrc так, чтобы он содержал «export SOURCED_SYSTEM_ETC_BASHRC = yes», и эта переменная появилась в журнале Jenkins для узла. Так что в моем случае, чтобы установить переменные окружения для подчиненных jenkins, они должны идти в / etc / bashrc. Вход в систему с помощью Jenkins ssh осуществляется только из / etc / bashrc.
Кодер Роуди
Исправление: я имел в виду /etc/bash.bashrc, а не / etc / bashrc.
Кодер Роуди
37
Это довольно стена текста, думаю, стоит выделить, что ssh user@host "bash --login -c 'command arg1 ...'"заставит удаленную оболочку настроить среду входа в систему. Упомянутый вами раздел упоминается, --loginно было бы легко пропустить это.
Codebeard
Спасибо за этот пост, я использовал ssh <ssh options> <IP> bash --login my_script.shдля запуска сценария на удаленной машине, работает угощение и позволил мне успешно использовать локальные переменные env, какJAVA_HOME
markc
117

Как насчет поиска профиля перед запуском команды?

ssh user@host "source /etc/profile; /path/script.sh"

Вы можете обнаружить , что лучше изменить , что ~/.bash_profile, ~/.bashrcили любой другой .

(Как здесь (linuxquestions.org) )

Ян Воган
источник
1
Если бы эта проблема, это решение работало отлично.
Sam152
10
Необходимость всегда вводить дополнительный код просто для получения исходных текстов - это просто смешно!
Michael
4
Один редко повторяет подобные вещи, обычно это происходит внутри скрипта, и, как таковое, не имеет значения, сколько там «дополнительного кода», пока он работает: tm:
Ian Vaughan
1
Если я использую / etc / profile и ~ / .bash_profile (чтобы получить пользовательские дополнения к пути), это работает, но это ужасно. Должен быть более простой способ указать команде (в моем случае xterm) использовать «интерактивный» вход в систему и получить полный пользовательский путь на удаленной машине?
Джесс
ssh $ 1 "source ~ / .bashrc; ~ / temp_unix.sh" Здесь temp_unix.sh имеет экспорт MANI_HOME = "mani deepak", но он не работает.
Мани Дипак
90

Среда оболочки не загружается при запуске удаленной команды ssh. Вы можете редактировать файл окружения ssh:

vi ~/.ssh/environment

Его формат:

VAR1=VALUE1
VAR2=VALUE2

Кроме того, проверьте sshdконфигурацию для PermitUserEnvironment=yesварианта.

dpedro
источник
1
совершенство! +100, если бы я мог :)
Декстер
Сбой VisualGDB с ошибкой «bash: gcc: команда не найдена», и это решение исправило это.
KalenGi
фантастика. Жаль, что я не знал об этом много лет назад.
гравитация
Это идеальный ответ!
Jirapong
1
@ pg2455, хотя вы не всегда можете настроить sshd на своем сервере (или не хотите включать его для всех), вы все равно можете редактировать свою пользовательскую среду
dpedro
63

У меня была похожая проблема, но в итоге я узнал, что ~ / .bashrc - это все, что мне нужно.

Однако в Ubuntu мне пришлось прокомментировать строку, которая останавливает обработку ~ / .bashrc:

#If not running interactively, don't do anything
[ -z "$PS1" ] && return
tomaszbak
источник
8
Кроме того, вы можете просто поместить весь свой «неинтерактивный» код выше этой строки.
machineghost
красивый, сэкономил мне много времени :) спасибо
Ланс Поллард
Спасибо. Просто добавив, что файл с оператором возврата можно найти по адресу /etc/bash.bashrc.
adarshr
Есть ли способ обойти этот код на сервере, не меняя его?
Йони
Я потратил так много времени, пытаясь понять, почему мой сценарий не работает. Кто думал, что было бы неплохо поместить эти строки в .bashrc ???
Шарку
4

Я нашел простое решение этой проблемы - добавить исходный файл / etc / profile в начало файла script.sh, который я пытался запустить в целевой системе. В системах здесь это привело к тому, что переменные окружения, которые были необходимы для script.sh, были настроены так, как если бы они запускались из оболочки входа.

В одном из предыдущих ответов было предложено использовать ~ / .bashr_profile и т. Д. Я не тратил много времени на это, но проблема в том, что если вы используете ssh для другого пользователя в целевой системе, а не для оболочки исходной системы, из которой вы вошли, мне показалось, что это вызывает пользователя исходной системы. имя, которое будет использоваться для ~.

цыпленок
источник
Отлично! Хорошее однострочное решение проблемы.
Корпорация
3

Просто экспортируйте переменные окружения, которые вы хотите, перед проверкой неинтерактивной оболочки в ~ / .bashrc.

Майкл Макдональд
источник