The “exec” channel in the JSch (rightfully) does not allocate a pseudo terminal (PTY) for the session. As a consequence a different set of startup scripts is (might be) sourced (particularly for non-interactive sessions, .bash_profile
is not sourced). And/or different branches in the scripts are taken, based on absence/presence of the TERM
environment variable. So the environment might differ from the interactive session, you use with your SSH client.
So, in your case, the PATH
is probably set differently; and consequently the air
executable cannot be found.
To verify that this is the root cause, disable the pseudo terminal allocation in your SSH client. For example in PuTTY, it’s Connection > SSH > TTY > Don’t allocate a pseudo terminal. Then, go to Connection > SSH > Remote command and enter your air ...
command. Check Session > Close window on exit > Never and open the session. You should get the same “air not found” error.
Ways to fix this, in preference order:
-
Fix the command not to rely on a specific environment. Use a full path to
air
in the command. E.g.:/bin/air sandbox run <graph-path>
If you do not know the full path, on common *nix systems, you can use
which air
command in your interactive SSH session. -
Fix your startup scripts to set the
PATH
the same for both interactive and non-interactive sessions. -
Try running the script explicitly via login shell (use
--login
switch with common *nix shells):bash --login -c "air sandbox run sandbox run <graph-path>"
-
If the command itself relies on a specific environment setup and you cannot fix the startup scripts, you can change the environment in the command itself. Syntax for that depends on the remote system and/or the shell. In common *nix systems, this works:
String command="PATH=\"$PATH;/path/to/air\" && air sandbox run <graph-path>";
-
Another (not recommended) approach is to force the pseudo terminal allocation for the “exec” channel using the
.setPty
method:Channel channel = session.openChannel("exec"); ((ChannelExec)channel).setPty(true);
Using the pseudo terminal to automate a command execution can bring you nasty side effects. See for example Is there a simple way to get rid of junk values that come when you SSH using Python’s Paramiko library and fetch output from CLI of a remote machine?
For a similar issues, see
- Certain Unix commands fail with “… not found”, when executed through Java using JSch even with setPty enabled
- Commands executed using JSch behaves differently than in SSH terminal (bypasses confirm prompt message of “yes/”no”)
- JSch: Is there a way to expose user environment variables to “exec” channel?
- Command (.4gl) executed with SSH.NET SshClient.RunCommand fails with “No such file or directory”