Certos comandos Unix falham com “… not found”, quando executados via Java usando o JSch

Eu tenho um pedaço de código que se conecta a um servidor Unix e executa comandos.

Eu tenho tentado com comandos simples e eles funcionam bem.

Eu sou capaz de logar e obter a saída dos comandos.

Eu preciso executar um grafo Ab initio através de Java.

Estou usando o comando air sandbox run graph para isso.

Ele funciona bem, quando eu faço o login usando o cliente SSH e executo o comando. Eu sou capaz de executar o gráfico. No entanto, quando eu tento executar o comando através de Java, ele me dá um erro de “ar não encontrado” .

Existe algum tipo de limite em que tipo de comandos Unix o JSch suporta?

Alguma idéia porque eu não sou capaz de executar o comando através do meu código Java?

Aqui está o código:

 public static void connect(){ try{ JSch jsch=new JSch(); String host="*****"; String user="*****"; String config = "Host foo\n"+ " User "+user+"\n"+ " Hostname "+host+"\n"; ConfigRepository configRepository = com.jcraft.jsch.OpenSSHConfig.parse(config); jsch.setConfigRepository(configRepository); Session session=jsch.getSession("foo"); String passwd ="*****"; session.setPassword(passwd); UserInfo ui = new MyUserInfo(){ public boolean promptYesNo(String message){ int foo = 0; return foo==0; } }; session.setUserInfo(ui); session.connect(); String command="air sandbox run "; Channel channel=session.openChannel("exec"); ((ChannelExec)channel).setCommand(command); channel.setInputStream(null); ((ChannelExec)channel).setErrStream(System.err); InputStream in=channel.getInputStream(); channel.connect(); byte[] tmp=new byte[1024]; while(true){ while(in.available()>0){ int i=in.read(tmp, 0, 1024); if(i0) continue; System.out.println("exit-status: "+channel.getExitStatus()); break; } try{Thread.sleep(1000);}catch(Exception ee){} } channel.disconnect(); session.disconnect(); } catch(Exception e){ System.out.println(e); } } public static void main(String arg[]){ connect(); } public String return_message(){ String ret_message=page_message; return ret_message; } public static abstract class MyUserInfo implements UserInfo, UIKeyboardInteractive{ public String getPassword(){ return null; } public boolean promptYesNo(String str){ return false; } public String getPassphrase(){ return null; } public boolean promptPassphrase(String message){ return false; } public boolean promptPassword(String message){ return false; } public void showMessage(String message){ } public String[] promptKeyboardInteractive(String destination, String name, String instruction, String[] prompt, boolean[] echo){ return null; } } 

O canal “exec” no JSch (por direito) não aloca um pseudo-terminal (PTY) para a session. Como consequência, um conjunto diferente de scripts de boot é (pode ser) originado (particularmente para sessões não interativas, o .bash_profile não é originado). E / ou diferentes ramos nos scripts são tomados, com base na ausência / presença da variável de ambiente TERM . Assim, o ambiente pode diferir da session interativa usada com o seu cliente SSH.

Então, no seu caso, o PATH é provavelmente definido de forma diferente; e consequentemente o executável air não pode ser encontrado.

Para verificar se esta é a causa raiz, desative a alocação do pseudo-terminal em seu cliente SSH. Por exemplo, no PuTTY, é Conexão> SSH> TTY> Não alocar um pseudo terminal . Em seguida, vá para Conexão> SSH> Comando Remoto e digite seu comando air ... Marque Sessão> Fechar janela ao sair> Nunca e abra a session. Você deve obter o mesmo erro “ar não encontrado” .


Formas de corrigir isso, na ordem de preferência:

  1. Corrija o comando para não depender de um ambiente específico. Use um caminho completo para o air no comando.

  2. Corrija seus scripts de boot para definir o PATH o mesmo para sessões interativas e não interativas.

  3. Tente executar o script explicitamente via shell de login (use --login switch com shells comuns * nix):

     bash --login -c "air sandbox run" 
  4. Se o comando se basear em uma configuração de ambiente específica e você não puder corrigir os scripts de boot, poderá alterar o ambiente no próprio comando. A syntax para isso depende do sistema remoto e / ou do shell. Em sistemas comuns * nix, isso funciona:

     String command="PATH=\"$PATH;/path/to/air\" && air sandbox run "; 
  5. Outra abordagem (não recomendada) é forçar a alocação pseudo-terminal para o canal “exec” usando o método .setPty :

     Channel channel=session.openChannel("exec"); ((ChannelExec)channel).setPty(true); 

    Usar o pseudo-terminal para automatizar a execução de um comando pode trazer efeitos colaterais desagradáveis. Veja por exemplo Existe uma maneira simples de se livrar de valores indesejados que vêm quando você usa a biblioteca Paramiko do Python e obtém a saída da CLI de uma máquina remota?


Para problemas semelhantes, consulte

  • Certos comandos Unix falham com “… não encontrado”, quando executados através de Java usando JSch, mesmo com o setPty ativado
  • Os comandos executados usando o JSch se comportam de maneira diferente do terminal SSH (ignora a mensagem de confirmação de “sim / não”)
  • JSch: Existe uma maneira de expor as variables ​​de ambiente do usuário para o canal “exec”?

você poderia tentar descobrir onde “air” reside

 whereis air 

e, em seguida, use esse resultado.

algo como

 /usr/bin/air sandbox run graph 

Você pode usar um arquivo ~ / .ssh / environment para definir suas variables ​​AB_HOME e PATH.