Alcuni comandi Unix falliscono con “… not found”, se eseguito tramite Java usando JSch

Ho un pezzo di codice che si collega a un server Unix ed esegue i comandi.

Ho provato con semplici comandi e funzionano bene.

Sono in grado di accedere e ottenere l’output dei comandi.

Ho bisogno di eseguire un grafico Ab-initio tramite Java.

Sto usando il comando air sandbox run graph per questo.

Funziona bene, quando effettuo il login usando il client SSH ed eseguo il comando. Sono in grado di eseguire il grafico. Tuttavia, quando provo a eseguire il comando tramite Java, mi viene restituito un errore “aria non trovata” .

C’è qualche tipo di limite su quale tipo di comandi Unix supporta JSch?

Qualche idea sul perché non sono in grado di eseguire il comando attraverso il mio codice Java?

Ecco il codice:

 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; } } 

Il canale “exec” nel JSch (a buon diritto) non alloca uno pseudoterminale (PTY) per la sessione. Di conseguenza un diverso set di script di avvio è (potrebbe essere) originario (in particolare per le sessioni non interattive, .bash_profile non è di provenienza). E / o diversi rami negli script sono presi, in base all’assenza / presenza della variabile d’ambiente TERM . Pertanto, l’ambiente potrebbe differire dalla sessione intertriggers, utilizzata con il client SSH.

Quindi, nel tuo caso, il PATH è probabilmente impostato in modo diverso; e di conseguenza l’eseguibile non può essere trovato.

Per verificare che questa sia la causa principale, disabilitare l’allocazione dello pseudo terminal nel client SSH. Ad esempio in PuTTY, è Connection> SSH> TTY> Non allocare uno pseudo terminale . Quindi, andare su Connessione> SSH> Comando remoto e immettere il comando air ... Controlla sessione> Chiudi finestra all’uscita> Mai e apri la sessione. Dovresti ottenere lo stesso errore “aria non trovata” .


Modi per risolvere questo problema, in ordine di preferenza:

  1. Correggere il comando per non fare affidamento su un ambiente specifico. Utilizzare un percorso completo per air nel comando.

  2. Correggi i tuoi script di avvio per impostare il PATH allo stesso modo per entrambe le sessioni interattive e non interattive.

  3. Prova a eseguire lo script in modo esplicito tramite la shell di accesso (usa --login switch con comuni * shell nix):

     bash --login -c "air sandbox run" 
  4. Se il comando stesso si basa su una specifica configurazione dell’ambiente e non è ansible correggere gli script di avvio, è ansible modificare l’ambiente nel comando stesso. La syntax dipende dal sistema remoto e / o dalla shell. Nei comuni sistemi * nix, questo funziona:

     String command="PATH=\"$PATH;/path/to/air\" && air sandbox run "; 
  5. Un altro approccio (non raccomandato) consiste nel forzare la pseudoallocazione del terminale per il canale “exec” usando il metodo .setPty :

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

    L’uso dello pseudo-terminale per automatizzare l’esecuzione di un comando può provocare effetti collaterali sgradevoli. Vedi per esempio C’è un modo semplice per sbarazzarsi dei valori spazzatura che arrivano quando SSH utilizza la libreria Paramiko di Python e preleva l’output dalla CLI di una macchina remota?


Per problemi simili, vedi

  • Alcuni comandi Unix falliscono con “… not found”, se eseguito tramite Java usando JSch anche con setPty abilitato
  • I comandi eseguiti usando JSch si comportano in modo diverso rispetto al terminale SSH (ignora il messaggio di conferma di “sì /” no “)
  • JSch: Esiste un modo per esporre le variabili di ambiente dell’utente al canale “exec”?

potresti provare a scoprire dove si trova “aria”

 whereis air 

e quindi utilizzare questo risultato.

qualcosa di simile a

 /usr/bin/air sandbox run graph 

È ansible utilizzare un file ~ / .ssh / environment per impostare le variabili AB_HOME e PATH.