Por que um comando remoto SSH obtém menos variáveis ​​de ambiente quando executado manualmente? [fechadas]

239

Eu tenho um comando que roda bem se eu ssh em uma máquina e a executo, mas falha quando tento executá-la usando um comando ssh remoto como:

ssh user@IP <command>

Comparando a saída de "env" usando os dois métodos, resutls em diferentes ambientes. Quando efetuo login manualmente na máquina e executo env, recebo muito mais variáveis ​​de ambiente do que quando executo:

ssh user@IP "env"

Alguma idéia do porquê?

Tom Feiner
fonte
30
Por que exatamente essa pergunta é encerrada como fora de tópico?
jottr
13
Provavelmente porque não está relacionado à programação. Deveria ter sido movido para Superusuário em vez de fechado.
Daniel H no
8
bashnão é uma linguagem de script?
Dan Nissenbaum 06/04/19
No Debian 8, tive que mudar o shell para bash no / etc / passwd por algum motivo. Até a reconfiguração do traço para deixar / bin / sh apontar para o bash não ajudou.
user1050755

Respostas:

173

Existem diferentes tipos de conchas. O shell de execução do comando SSH é um shell não interativo, enquanto o seu shell normal é um shell de logon ou um shell interativo. Descrição a seguir, do man bash:

       Um shell de login é aquele cujo primeiro caractere de argumento
       zero é um - ou foi iniciado com a opção --login.

       Um shell interativo é aquele iniciado sem opção
       argumentos e sem a opção -c cuja entrada padrão
       e erro estão conectados aos terminais (conforme determinado
       por isatty (3)) ou um iniciado com a opção -i. PS1 é
       set e $ - inclui i se o bash for interativo, permitindo uma
       shell script ou um arquivo de inicialização para testar esse estado.

       Os parágrafos a seguir descrevem como o bash executa sua
       arquivos de inicialização. Se algum dos arquivos existir, mas não puder ser
       ler, bash relata um erro. Tildes são expandidos em arquivo
       nomes descritos abaixo em Expansão Tilde no
       Seção de expansão.

       Quando o bash é chamado como um shell de logon interativo ou como
       um shell não interativo com a opção --login, primeiro
       lê e executa comandos do arquivo / etc / profile, se
       esse arquivo existe. Depois de ler esse arquivo, ele procura
       ~ / .bash_profile, ~ / .bash_login e ~ / .profile, nesse
       ordem e lê e executa comandos desde o primeiro
       que existe e é legível. A opção --noprofile pode
       ser usado quando o shell for iniciado para inibir esse comportamento
       eu ou.

       Quando um shell de login sai, o bash lê e executa comandos
       do arquivo ~ / .bash_logout, se existir.

       Quando um shell interativo que não é um shell de logon é
       iniciado, o bash lê e executa comandos de ~ / .bashrc,
       se esse arquivo existir. Isso pode ser inibido usando o
       opção --norc. A opção de arquivo --rcfile forçará o bash
       para ler e executar comandos do arquivo em vez de
       ~ / .bashrc.

       Quando o bash é iniciado de maneira não interativa, para executar um shell
       script, por exemplo, procura a variável BASH_ENV em
       ambiente, expande seu valor se aparecer lá,
       e usa o valor expandido como o nome de um arquivo para ler
       e executar. O bash se comporta como se o seguinte comando
       foram executados:
              if [-n "$ BASH_ENV"]; então . "$ BASH_ENV"; fi
       mas o valor da variável PATH não é usado para procurar
       para o nome do arquivo.

Vinko Vrsalovic
fonte
7
Ótima resposta, esse era exatamente o problema, as variáveis ​​de ambiente necessárias residiam no / etc / bashrc, que não são originadas no modo não interativo. Movê-los para / etc / profile resolveu o problema. Muito obrigado!
Tom Feiner
1
Esta resposta é apenas uma solução parcial. Aqui estão mais algumas informações: adicione uma variável de ambiente diferente (por exemplo, exporte SOURCED_SYSTEM_ETC_BASHRC) aos vários arquivos que são obtidos: / etc / profile, etc / bashrc, ~ / .profile, ~ / .bash_profile, ~ / bashrc. Em seguida, procure essa variável exclusiva na saída Jenkins. No meu caso, atualizei o / etc / bashrc para conter 'export SOURCED_SYSTEM_ETC_BASHRC = yes' e essa variável apareceu no log do Jenkins para o nó. Portanto, no meu caso, para definir variáveis ​​de ambiente para os escravos jenkins, eles precisam entrar no / etc / bashrc. O login do Jenkins ssh apenas originou / etc / bashrc.
Coder Roadie
Correção: eu quis dizer /etc/bash.bashrc, não / etc / bashrc.
Coder Roadie
37
Isso é uma parede de texto, acho que vale a pena destacar que ssh user@host "bash --login -c 'command arg1 ...'"fará com que o shell remoto configure o ambiente de login. A seção que você citou menciona, --loginmas seria fácil ignorar isso.
Codebeard
Obrigado por este post, eu costumava ssh <ssh options> <IP> bash --login my_script.shexecutar um script na máquina remota, trabalha um tratamento e me permitiu usar com êxito ambientes locais comoJAVA_HOME
markc
117

Que tal obter o perfil antes de executar o comando?

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

Você pode achar que é melhor para mudar isso para ~/.bash_profile, ~/.bashrcou o que quer.

(Como aqui (linuxquestions.org) )

Ian Vaughan
fonte
1
Teve este problema, esta solução funcionou muito bem.
Sam152 25/05
10
Ter que sempre digitar um código extra apenas para fornecer origem ao ambiente é ridículo!
Michael Michael
4
Raramente se digita esse tipo de coisa repetidamente, normalmente estaria em um script e, como tal, não importa quanto "código extra" exista, desde que funcione: tm:
Ian Vaughan
1
Se eu for fonte de / etc / profile e ~ / .bash_profile (para incluir adições de usuário no caminho), ele funciona, mas é feio. Deve haver uma maneira mais fácil de dizer ao comando (no meu caso xterm) para usar o logon "interativo" e terminar com o caminho específico do usuário completo na máquina remota?
21413 Jess
ssh $ 1 "fonte ~ / .bashrc; ~ / temp_unix.sh" Aqui o temp_unix.sh exporta MANI_HOME = "mani deepak", mas não está funcionando.
mani deepak
90

O ambiente do shell não carrega ao executar o comando ssh remoto. Você pode editar o arquivo de ambiente ssh:

vi ~/.ssh/environment

Seu formato é:

VAR1=VALUE1
VAR2=VALUE2

Além disso, verifique a sshdconfiguração para a PermitUserEnvironment=yesopção.

dpedro
fonte
1
perfeição! +100 se eu pudesse :)
Dexter
O VisualGDB estava falhando com o erro "bash: gcc: command not found" e esta solução corrigiu isso.
KalenGi
fantástico. gostaria de saber sobre isso anos atrás.
gravitação
Esta é a resposta perfeita!
precisa saber é o seguinte
1
@ pg2455 enquanto você nem sempre são capazes de sshd configure em seu servidor (ou não quiser habilitá-lo para todos), você ainda pode editar o seu ambiente de usuário
dpedro
63

Eu tive um problema semelhante, mas no final descobri que ~ / .bashrc era tudo que eu precisava.

No entanto, no Ubuntu, tive que comentar a linha que para de processar ~ / .bashrc:

#If not running interactively, don't do anything
[ -z "$PS1" ] && return
tomaszbak
fonte
8
Como alternativa, você pode simplesmente colocar todo o seu código "não interativo" acima dessa linha.
precisa
bonito, me salvou um monte de tempo :) Obrigado
Lance Pollard
Obrigado. Basta adicionar que o arquivo com a declaração de retorno pode ser encontrado em /etc/bash.bashrc.
adarshr
Existe alguma maneira de ignorar esse código no servidor sem alterá-lo?
Yoni
Passei tanto tempo tentando entender por que meu script não funcionou. Quem achou que era uma boa ideia colocar essas linhas no .bashrc ???
Sharcoux
4

Encontrei uma solução fácil para esse problema: adicionar código-fonte / etc / profile à parte superior do arquivo script.sh que eu estava tentando executar no sistema de destino. Nos sistemas aqui, isso fez com que as variáveis ​​ambientais necessárias ao script.sh fossem configuradas como se estivessem sendo executadas a partir de um shell de login.

Em uma das respostas anteriores, sugeriu-se que ~ / .bashr_profile etc ... fosse usado. Não gastei muito tempo com isso, mas o problema é que se você fizer um shsh para um usuário diferente no sistema de destino do que o shell no sistema de origem no qual você efetua login, me pareceu que isso causa o usuário do sistema de origem nome a ser usado para o ~.

Mandril
fonte
Perfeito! Ótima solução de uma linha para o problema.
corpico
3

Apenas exporte as variáveis ​​de ambiente que você deseja acima da verificação para um shell não interativo em ~ / .bashrc.

Michael MacDonald
fonte