Perché un comando remoto SSH ottiene meno variabili di ambiente rispetto all'esecuzione manuale? [chiuso]


239

Ho un comando che funziona bene se eseguo SSH su una macchina ed eseguo, ma fallisce quando provo ad eseguirlo usando un comando remoto ssh come:

ssh user@IP <command>

Confrontando l'output di "env" utilizzando entrambi i metodi, si verifica il risultato in diversi ambienti. Quando accedo manualmente alla macchina ed eseguo env, ottengo molte più variabili di ambiente rispetto a quando eseguo:

ssh user@IP "env"

Qualche idea sul perché?


30
Perché esattamente questa domanda è chiusa come fuori tema?
jottr,

13
Probabilmente perché non è legato alla programmazione. Dovrebbe essere stato spostato su Super User anziché chiuso.
Daniel H

8
bashnon è un linguaggio di scripting?
Dan Nissenbaum,

In Debian 8 ho dovuto cambiare la shell per bash in / etc / passwd per qualche motivo. Anche la riconfigurazione del trattino per lasciare che / bin / sh punti a bash non ha aiutato.
user1050755

Risposte:


173

Esistono diversi tipi di shell. La shell di esecuzione del comando SSH è una shell non interattiva, mentre la shell normale è una shell di accesso o una shell interattiva. Segue la descrizione, da man bash:

       Una shell di login è quella il cui primo carattere di argomento
       zero è un - o uno è iniziato con l'opzione --login.

       Una shell interattiva è quella avviata senza opzione
       argomenti e senza l'opzione -c il cui input standard
       e l'errore sono entrambi collegati ai terminali (come determinato
       di isatty (3)), oppure uno è iniziato con l'opzione -i. PS1 è
       set e $ - include i se bash è interattivo, consentendo a
       shell script o un file di avvio per testare questo stato.

       I seguenti paragrafi descrivono come bash esegue i suoi
       file di avvio. Se uno dei file esiste ma non può esserlo
       leggi, bash segnala un errore. Le tilde sono espanse nel file
       nomi come descritto di seguito in Tilde Expansion in
       Sezione ESPANSIONE.

       Quando bash viene invocato come shell di login interattiva o come
       una shell non interattiva con l'opzione --login, per prima cosa
       legge ed esegue i comandi dal file / etc / profile, se
       quel file esiste. Dopo aver letto quel file, lo cerca
       ~ / .bash_profile, ~ / .bash_login e ~ / .profile, in quello
       ordine, legge ed esegue i comandi dal primo
       che esiste ed è leggibile. L'opzione --noprofile può
       essere usato quando si avvia la shell per inibire questo comportamento
       IOR.

       Quando esce una shell di login, bash legge ed esegue i comandi
       dal file ~ / .bash_logout, se esiste.

       Quando è una shell interattiva che non è una shell di accesso
       avviato, bash legge ed esegue i comandi da ~ / .bashrc,
       se quel file esiste. Questo può essere inibito usando il
       opzione --norc. L'opzione --rcfile forzerà bash
       per leggere ed eseguire comandi dal file anziché
       ~ / .Bashrc.

       Quando bash viene avviato in modo non interattivo, per eseguire una shell
       script, ad esempio, cerca la variabile BASH_ENV in
       l'ambiente, espande il suo valore se appare lì,
       e utilizza il valore espanso come nome di un file da leggere
       ed eseguire. Bash si comporta come se il seguente comando
       furono giustiziati:
              if [-n "$ BASH_ENV"]; poi . "$ BASH_ENV"; fi
       ma il valore della variabile PATH non viene utilizzato per la ricerca
       per il nome del file.


7
Ottima risposta, questo era esattamente il problema, le variabili d'ambiente necessarie risiedevano in / etc / bashrc, che non proviene in modalità non interattiva. Spostandoli in / etc / profile ha risolto il problema. Grazie mille!
Tom Feiner,

1
Questa risposta è solo una soluzione parziale. Ecco alcune ulteriori informazioni: aggiungi una diversa variabile d'ambiente (es. Esportazione SOURCED_SYSTEM_ETC_BASHRC) ai vari file che ottengono: / etc / profile, etc / bashrc, ~ / .profile, ~ / .bash_profile, ~ / bashrc. Quindi cerca quella variabile unica nell'output di Jenkins. Nel mio caso, ho aggiornato / etc / bashrc per contenere 'export SOURCED_SYSTEM_ETC_BASHRC = yes' e quella variabile è stata mostrata nel registro Jenkins per il nodo. Quindi nel mio caso, per impostare le variabili di ambiente per gli slave jenkins devono andare in / etc / bashrc. Accesso jenkins ssh solo di provenienza / etc / bashrc.
Coder Roadie,

Correzione: intendevo /etc/bash.bashrc, non / etc / bashrc.
Coder Roadie,

37
È piuttosto un muro di testo, penso che varrebbe la pena sottolineare che ssh user@host "bash --login -c 'command arg1 ...'"renderà la shell remota configurata l'ambiente di accesso. La sezione che hai citato menziona --loginma sarebbe facile trascurarlo.
codebeard

Grazie per questo post, ho usato ssh <ssh options> <IP> bash --login my_script.shper eseguire uno script sul computer remoto, funziona a meraviglia e mi ha permesso di utilizzare con successo JAVA_HOME
varchi

117

Che ne dici di cercare il profilo prima di eseguire il comando?

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

Si potrebbe trovare migliore per cambiare la situazione a ~/.bash_profile, ~/.bashrc, o qualsiasi altra cosa.

(Come qui (linuxquestions.org) )


1
Ha avuto questo problema, questa soluzione ha funzionato alla grande.
Sam152,

10
Dover digitare sempre un codice aggiuntivo solo per generare l'ambiente è ridicolo!
Michael

4
Raramente si scrivono ripetutamente questo genere di cose, normalmente sarebbero all'interno di uno script, e come tali, non importa quanto "codice extra" ci sia, purché funzioni: tm:
Ian Vaughan

1
Se provo sia / etc / profile che ~ / .bash_profile (per ottenere le aggiunte dell'utente al percorso) funziona, ma è brutto. Ci deve essere un modo più semplice per dire al comando (nel mio caso xterm) di usare il login "interattivo" e finire con il percorso completo specifico dell'utente sulla macchina remota?
Jess

ssh $ 1 "source ~ / .bashrc; ~ / temp_unix.sh" Qui temp_unix.sh ha esportato MANI_HOME = "mani deepak" ma non funziona.
mani deepak

90

L'ambiente Shell non viene caricato quando si esegue il comando ssh remoto. È possibile modificare il file di ambiente ssh:

vi ~/.ssh/environment

Il suo formato è:

VAR1=VALUE1
VAR2=VALUE2

Inoltre, controlla la sshdconfigurazione per l' PermitUserEnvironment=yesopzione.


1
perfezione! +100 se potessi :)
Dexter

VisualGDB non funzionava con l'errore "bash: gcc: comando non trovato" e questa soluzione lo ha corretto.
KalenGi

fantastico. avrei voluto saperlo anni fa.
gravitazione

Questa è la risposta perfetta!
Jirapong,

1
@ pg2455 mentre non sei sempre in grado di configurare sshd sul tuo server (o non vuoi abilitarlo per tutti), puoi comunque modificare il tuo ambiente utente
dpedro

63

Ho avuto un problema simile, ma alla fine ho scoperto che ~ / .bashrc era tutto ciò di cui avevo bisogno.

Tuttavia, in Ubuntu, ho dovuto commentare la riga che interrompe l'elaborazione ~ / .bashrc:

#If not running interactively, don't do anything
[ -z "$PS1" ] && return

8
In alternativa, puoi semplicemente mettere tutto il tuo codice "non interattivo" sopra quella linea.
machineghost,

bellissimo, mi ha fatto risparmiare un sacco di tempo :) grazie
Lance Pollard,

Grazie. Basta aggiungere che il file con l'istruzione return può essere trovato su /etc/bash.bashrc.
Adarshr,

Esiste un modo per bypassare questo codice nel server senza modificarlo?
Yoni,

Ho trascorso così tanto tempo a cercare di capire perché la mia sceneggiatura non funzionava. Chi ha pensato che fosse una buona idea inserire queste righe nel .bashrc ???
Sharcoux,

4

Ho trovato una soluzione semplice per questo problema era aggiungere sorgente / etc / profile all'inizio del file script.sh che stavo cercando di eseguire sul sistema di destinazione. Sui sistemi qui, ciò ha causato la configurazione delle variabili ambientali necessarie per script.sh come se fossero in esecuzione da una shell di login.

In una delle risposte precedenti è stato suggerito di utilizzare ~ / .bashr_profile ecc .... Non ho trascorso molto tempo su questo, ma il problema è che se si invia a un utente diverso sul sistema di destinazione rispetto alla shell sul sistema di origine da cui si accede mi è sembrato che ciò causi l'utente del sistema di origine nome da usare per ~.


Perfetto! Bella soluzione a una riga al problema.
corpico,

3

Esporta semplicemente le variabili di ambiente che desideri sopra il controllo per una shell non interattiva in ~ / .bashrc.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.