Dlaczego komenda zdalna SSH otrzymuje mniej zmiennych środowiskowych niż wtedy, gdy jest uruchamiana ręcznie? [Zamknięte]

239

Mam polecenie, które działa poprawnie, jeśli ssh na maszynie i uruchomię go, ale kończy się niepowodzeniem, gdy próbuję uruchomić go za pomocą zdalnego polecenia ssh, takiego jak:

ssh user@IP <command>

Porównywanie danych wyjściowych „env” przy użyciu obu metod rozpoczyna się w różnych środowiskach. Kiedy ręcznie loguję się do komputera i uruchamiam env, otrzymuję znacznie więcej zmiennych środowiskowych niż wtedy, gdy uruchamiam:

ssh user@IP "env"

Masz pomysł, dlaczego?

Tom Feiner
źródło
30
Dlaczego dokładnie to pytanie jest zamknięte jako nie na temat?
jottr
13
Prawdopodobnie dlatego, że nie jest związany z programowaniem. Powinien zostać przeniesiony do superużytkownika zamiast zamknięty.
Daniel H
8
bashnie jest językiem skryptowym?
Dan Nissenbaum
W Debianie 8 z jakiegoś powodu musiałem zmienić powłokę na bash w / etc / passwd. Nawet ponowna konfiguracja myślnika, aby pozwolić / bin / sh wskazywać na bash, nie pomogła.
user1050755

Odpowiedzi:

173

Istnieją różne rodzaje muszli. Powłoka wykonania polecenia SSH jest powłoką nieinteraktywną, podczas gdy normalna powłoka jest powłoką logowania lub powłoką interaktywną. Opis pochodzi z man bash:

       Powłoka logowania to taka, której pierwszy znak argumentu
       zero jest - lub zaczyna się od opcji --login.

       Powłoka interaktywna to taka, która została uruchomiona bez opcji
       argumenty i bez opcji -c, której standardowe wejście
       i błąd są podłączone do zacisków (jak określono
       przez isatty (3)) lub taki, który zaczął się od opcji -i. PS1 jest
       set i $ - obejmuje i, jeśli bash jest interaktywny, pozwalając na
       skrypt powłoki lub plik startowy, aby przetestować ten stan.

       Poniższe akapity opisują, w jaki sposób bash wykonuje swoje
       pliki startowe. Jeśli któryś z plików istnieje, ale nie może być
       czytaj, bash zgłasza błąd. Tyldy są rozwijane w pliku
       nazwy jak opisano poniżej w części Rozbudowa tyldy w
       Sekcja ROZSZERZENIE.

       Gdy bash zostanie wywołany jako interaktywna powłoka logowania lub jako
       najpierw nieinteraktywna powłoka z opcją --login
       czyta i wykonuje polecenia z pliku / etc / profile, jeśli
       ten plik istnieje. Po przeczytaniu tego pliku szuka
       ~ / .bash_profile, ~ / .bash_login i ~ / .profile, w tym
       porządek oraz odczytuje i wykonuje polecenia z pierwszego
       który istnieje i jest czytelny. Opcja --noprofile może
       być używane, gdy powłoka jest uruchamiana w celu zahamowania tego zachowania
       ior.

       Po wyjściu z powłoki logowania bash czyta i wykonuje polecenia
       z pliku ~ / .bash_logout, jeśli istnieje.

       Gdy jest to powłoka interaktywna, która nie jest powłoką logowania
       uruchomione, bash czyta i wykonuje polecenia z ~ / .bashrc,
       jeśli ten plik istnieje. Można to zahamować za pomocą
       --norc opcja. Opcja pliku --rcfile wymusi bash
       do czytania i wykonywania poleceń z pliku zamiast
       ~ / .bashrc.

       Gdy bash jest uruchamiany nieinteraktywnie, aby uruchomić powłokę
       skrypt na przykład szuka zmiennej BASH_ENV w
       środowisko rozszerza swoją wartość, jeśli się tam pojawia,
       i używa rozszerzonej wartości jako nazwy pliku do odczytu
       i wykonać. Bash zachowuje się tak, jakby następujące polecenie
       zostały wykonane:
              jeśli [-n "$ BASH_ENV"]; następnie . „$ BASH_ENV”; fi
       ale wartość zmiennej PATH nie jest używana do wyszukiwania
       dla nazwy pliku.

Vinko Vrsalovic
źródło
7
Świetna odpowiedź, to był właśnie problem, potrzebne zmienne środowiskowe znajdowały się w / etc / bashrc, który nie jest pozyskiwany w trybie nieinteraktywnym. Przeniesienie ich do / etc / profile rozwiązało problem. Dziękuję Ci bardzo!
Tom Feiner,
1
Ta odpowiedź jest tylko częściowym rozwiązaniem. Oto kilka informacji: dodaj inną zmienną środowiskową (np. Eksportuj SOURCED_SYSTEM_ETC_BASHRC) do różnych plików, które są pozyskiwane: / etc / profile, etc / bashrc, ~ / .profile, ~ / .bash_profile, ~ / bashrc. Następnie poszukaj tej unikalnej zmiennej w danych wyjściowych Jenkins. W moim przypadku zaktualizowałem / etc / bashrc, aby zawierał „export SOURCED_SYSTEM_ETC_BASHRC = tak”, i ta zmienna pojawiła się w dzienniku Jenkinsa dla węzła. Tak więc w moim przypadku, aby ustawić zmienne środowiskowe dla jenkins slaves, muszą przejść do / etc / bashrc. Logowanie do Jenkins ssh pochodziło tylko z / etc / bashrc.
Coder Roadie
Poprawka: miałem na myśli /etc/bash.bashrc, nie / etc / bashrc.
Coder Roadie
37
To dość ściana tekstu, myślę, że warto podkreślić, że ssh user@host "bash --login -c 'command arg1 ...'"zdalna powłoka skonfiguruje środowisko logowania. W cytowanej części wspomina się, --loginale łatwo byłoby to przeoczyć.
codebeard
Dziękuję za ten post, kiedyś ssh <ssh options> <IP> bash --login my_script.shuruchamiałem skrypt na zdalnej maszynie, działa uczta i umożliwiłem mi skuteczne korzystanie z lokalnych zmiennych env, takich jakJAVA_HOME
markc
117

Co powiesz na pozyskanie profilu przed uruchomieniem polecenia?

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

Może się okazać, że najlepiej to zmienić, aby ~/.bash_profile, ~/.bashrcczy cokolwiek innego.

(Jak tutaj (linuxquestions.org) )

Ian Vaughan
źródło
1
Gdyby ten problem działał świetnie.
Sam152,
10
Konieczność wpisywania dodatkowego kodu tylko w celu pozyskania środowiska jest absurdalna!
Michael
4
Rzadko wpisuje się tego rodzaju rzeczy, zwykle byłoby to w skrypcie i jako takie nie ma znaczenia, ile jest „dodatkowego kodu”, o ile działa: tm:
Ian Vaughan
1
Jeśli pozyskuję zarówno / etc / profile, jak i ~ / .bash_profile (aby uzyskać dodatki użytkowników do ścieżki), to działa, ale jest brzydkie. Musi istnieć łatwiejszy sposób na polecenie (w moim przypadku xterm) użycia „interaktywnego” logowania i uzyskania pełnej ścieżki użytkownika na zdalnym komputerze?
Jess,
ssh $ 1 "source ~ / .bashrc; ~ / temp_unix.sh" Tutaj temp_unix.sh ma eksport MANI_HOME = "mani deepak", ale nie działa.
mani deepak
90

Środowisko powłoki nie ładuje się podczas uruchamiania zdalnego polecenia ssh. Możesz edytować plik środowiska ssh:

vi ~/.ssh/environment

Jego format to:

VAR1=VALUE1
VAR2=VALUE2

Sprawdź także sshdkonfigurację PermitUserEnvironment=yesopcji.

dpedro
źródło
1
doskonałość! +100, gdybym mógł :)
Dexter,
Błąd VisualGDB z błędem „bash: gcc: polecenie nie znaleziono” i rozwiązanie to naprawiło.
KalenGi
fantastyczny. chciałbym wiedzieć o tym lata temu.
grawitacja
To idealna odpowiedź!
Jirapong
1
@ pg2455, chociaż nie zawsze możesz skonfigurować sshd na swoim serwerze (lub nie chcesz włączać go dla wszystkich), nadal możesz edytować środowisko użytkownika
dpedro
63

Miałem podobny problem, ale w końcu dowiedziałem się, że ~ / .bashrc było wszystkim, czego potrzebowałem.

Jednak w Ubuntu musiałem skomentować linię, która przestaje przetwarzać ~ / .bashrc:

#If not running interactively, don't do anything
[ -z "$PS1" ] && return
tomaszbak
źródło
8
Alternatywnie możesz po prostu umieścić cały swój „nieinteraktywny” kod powyżej tej linii.
machineghost
piękna, zaoszczędziła mi dużo czasu :) dzięki
Lance Pollard,
Dzięki. Wystarczy dodać, że plik z instrukcją return można znaleźć pod adresem /etc/bash.bashrc.
adarshr
Czy w ogóle można ominąć ten kod na serwerze bez jego zmiany?
Yoni
Spędziłem dużo czasu próbując zrozumieć, dlaczego mój skrypt nie działa. Kto pomyślał, że dobrym pomysłem jest umieszczenie tych wierszy w pliku .bashrc ???
Sharcoux
4

Odkryłem, że łatwym rozwiązaniem tego problemu było dodanie źródła / etc / profile na górze pliku script.sh, który próbowałem uruchomić w systemie docelowym. W systemach tutaj spowodowało to, że zmienne środowiskowe potrzebne skryptowi.sh zostały skonfigurowane tak, jakby działały z powłoki logowania.

W jednej z wcześniejszych odpowiedzi zasugerowano użycie ~ / .bashr_profile itp ... Nie spędziłem dużo czasu na tym, ale problem polega na tym, że ssh do innego użytkownika w systemie docelowym niż powłoka w systemie źródłowym, z którego się logujesz, wydaje mi się, że powoduje to użytkownika systemu źródłowego nazwa używana dla ~.

Głaskanie pod brodę
źródło
Idealny! Ładne, jednoliniowe rozwiązanie problemu.
corpico,
3

Po prostu wyeksportuj zmienne środowiskowe, które chcesz powyżej sprawdzania nieinteraktywnej powłoki w ~ / .bashrc.

Michael MacDonald
źródło