Ciertos comandos de Unix fallan con “… no encontrado”, cuando se ejecutan a través de Java utilizando JSch

Tengo un código que se conecta a un servidor Unix y ejecuta comandos.

He estado intentando con comandos simples y funcionan bien.

Puedo iniciar sesión y obtener la salida de los comandos.

Necesito ejecutar un gráfico Ab-initio a través de Java.

Estoy usando el comando air sandbox run graph para esto.

Funciona bien, cuando inicio sesión usando el cliente SSH y ejecuto el comando. Puedo ejecutar el gráfico. Sin embargo, cuando trato de ejecutar el comando a través de Java me da un error de “air no encontrado” .

¿Hay algún tipo de límite en el tipo de comandos de Unix que admite JSch?

¿Alguna idea de por qué no puedo ejecutar el comando a través de mi código Java?

Aquí está el 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; } } 

El canal “exec” en el JSch (con razón) no asigna un pseudo terminal (PTY) para la sesión. Como consecuencia, un conjunto diferente de scripts de inicio es (podría ser) de origen (sobre todo para las sesiones no interactivas, .bash_profile no se origina). Y / o se toman diferentes twigs en los scripts, en función de la ausencia / presencia de la variable de entorno TERM . Por lo tanto, el entorno puede diferir de la sesión interactiva que usa con su cliente SSH.

Entonces, en tu caso, el PATH probablemente esté configurado de manera diferente; y, en consecuencia, el ejecutable air no se puede encontrar.

Para verificar que esta es la causa raíz, deshabilite la asignación de pseudo-terminal en su cliente SSH. Por ejemplo, en PuTTY, es Conexión> SSH> TTY> No asignar un pseudo terminal . Luego, vaya a Connection> SSH> Remote command e ingrese su comando air ... Marque Sesión> Cerrar ventana al salir> Nunca y abra la sesión. Debería obtener el mismo error de “air no encontrado” .


Formas de arreglar esto, en orden de preferencia:

  1. Arregle el comando para no confiar en un entorno específico. Use una ruta completa para air en el comando.

  2. Repare sus scripts de inicio para configurar PATH igual para sesiones interactivas y no interactivas.

  3. Intente ejecutar el script explícitamente a través del shell de inicio de sesión (use --login switch con common * nix shells):

     bash --login -c "air sandbox run" 
  4. Si el comando se basa en una configuración de entorno específica y no puede corregir los scripts de inicio, puede cambiar el entorno en el comando mismo. La syntax para eso depende del sistema remoto y / o el shell. En los sistemas * nix comunes, esto funciona:

     String command="PATH=\"$PATH;/path/to/air\" && air sandbox run "; 
  5. Otro enfoque (no recomendado) es forzar la asignación de pseudo-terminal para el canal “exec” usando el método .setPty :

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

    Usar el pseudo terminal para automatizar la ejecución de un comando puede traerle desagradables efectos secundarios. Ver, por ejemplo, ¿hay una forma simple de deshacerse de los valores basura que vienen cuando SSH usa la biblioteca Paramiko de Python y obtiene la salida de la CLI de una máquina remota?


Para un problema similar, ver

  • Ciertos comandos de Unix fallan con “… no encontrado”, cuando se ejecutan a través de Java utilizando JSch incluso con setPty activado
  • Los comandos ejecutados usando JSch se comportan de forma diferente que en el terminal SSH (omite confirmar mensaje de mensaje de “sí /” no “)
  • JSch: ¿Hay alguna manera de exponer las variables del entorno del usuario al canal “ejecutivo”?

podrías intentar averiguar dónde reside el “air”

 whereis air 

y luego usa este resultado

algo como

 /usr/bin/air sandbox run graph 

Puede usar un archivo ~ / .ssh / environment para establecer sus variables AB_HOME y PATH.