Differencebetween the 'Shell' Channel and the 'Exec' Channel in Jsch

What is the difference between the 'shell' channel and the 'exec' channel in JSch

With shell channel the shell (on unix it's sh or bash or something like that, on Windows it's usually cmd.exe) is started and console is created (the same you see on the screen if you run them locally). You have a prompt which you can parse or use for detection of completion of command.

With command channel a shell instance is started for each command (actually the channel is opened for each command) and a command is passed as a parameter for the shell (on Windows it would look like "cmd.exe /c ".

It's easier to use command channel cause you don't need to deal with command prompt.

what's the exact differences between jsch ChannelExec and ChannelShell?

The shell and exec channels are quite similar - both execute commands with the remote shell (at least, conceptually - the server might be configured to treat them differently, of course). RFC 4254 groups them in the section "Interactive Sessions", and they both (as well as subsystem, see below) use the channel type "session" in the SSH protocol.

There is one important difference:

  • For ChannelShell, the input stream provides both the commands and input to these commands. This is like using an interactive shell on your local computer. (And it is normally used just for that: interactive use.)

  • For ChannelExec, the commands are given with setCommand() before connect(), and the input stream will be forwarded to these commands as input. (Most often, you will have only one command, but you can provide multiple ones using the normal shell separators &, &&, |, ||, ;, newline, and compound commands.) This is like executing a shell script on your local computer. (Of course, if one of the commands itself is an interactive shell, this will behave like a ChannelShell.)

  • There is a third similar one, ChannelSubsystem, which executes a subsystem of the ssh server - here the server's configuration decides what to do, not the remote user's shell. (The most often used subsystem is sftp, but for this JSch provides a specialized channel, which understands the protocol.)

Note that what I call "input stream" here is the stream of data in the channel from the local to the remote host – that can be actually be done by passing a Java InputStream to the setInputStream method, or by getting a Java OutputStream from the getOutputStream method and writing to it.

Performance takes a hit while using Java JSch exec vs shell to run multiple commands?

Yes, that's quite likely. The "exec" channel runs the command in an isolated environment (typically a new shell instance).

Setting up the environment on the server will likely take some time.

So it most likely has nothing to do with your Java code.

Why does reading from a shell channel output in JSch never end with -1?

The "shell" channel opens a shell.

We do not know what your code actually does. But I'd assume that you send some command to the shell to be executed and then you try to read the command output. And you probably expect to get -1 once the command output ends. You won't.

The shell output stream ends, only when the shell ends. And for that you need to send some command like exit.


In general, you should not use the "shell" channel. It's intended for implementing an interactive shell session (like if you are implementing your own SSH terminal). That's something you rarely do.

To automate a command execution, use the "exec" channel.

See also What is the difference between the 'shell' channel and the 'exec' channel in JSch.

Executing multiple commands over SSH exec channel on firewall device with Java JSch does not work

The "exec" channel on your device seems to be implemented incorrectly. So you cannot use your code with the "exec" channel. As you can "ssh" to the device, it seems that the "shell" channel is fully working. Try talking to your server administrator, to get the server fixed.

If fixing the server is not feasible, you will have to revert to using the "shell" channel, although it is generally not the correct way to implement command automation.

See What is the difference between the 'shell' channel and the 'exec' channel in JSch

JSch by default enables terminal emulation for the "shell" channel, what will bring lot of unwanted side effects (see Getting unwanted characters when reading command output from SSH server using JSch). You may need to disable that by calling setPty.

ChannelShell channel = (ChannelShell) session.openChannel("shell"); 

InputStream in = channel.getInputStream();
outStream = channel.getOutputStream();

channel.setPty(false);
channel.connect();

outStream.write('configure\n'.getBytes());
outStream.write('move shared pre-rulebase security rules TEST top\n'.getBytes());

Get output of a specific command only in JSch shell channel

You have to read the output to some buffer/string. Then parse out and print only the part you want.

See How to get jsch shell command output in String.


There's no other way to separate output of individual commands. From an SSH client perspective, the shell is just a black box with input/output. There's no structure. The "shell" should not be use to automate command execution. You should use the "exec" channel. See also What is the difference between the 'shell' channel and the 'exec' channel in JSch.

In the "exec" channel, you execute each command independently, so you won't have problems separating their output. See How to read JSch command output?


Anyway, if you want to stick with your suboptimal "shell" solution, it helps, when you print some delimiter before and after the script like:

echo ---begin---
/.../myscript.sh
echo ---end---

What is the difference between exec_command and send with invoke_shell() on Paramiko?

The difference is that invoke_shell uses SSH shell channel, while exec_command uses SSH exec channel.

What that really means to you as a user/developer really depends on the SSH server, not on Paramiko itself.


In common *nix OpenSSH server:

  • The shell channel executes a login shell (as if you login with SSH terminal client). The shell will then present a command prompt and wait for client/user to type the commands. The purpose of the shell channel is to implement an interactive shell session. So basically it's legitimate use is an implementation of an SSH terminal client. That is something one will do very very rarely. If you do, you typically want to use terminal emulation (Paramiko invoke_shell does that unconditionally, but actually it's possible to open the shell channel without the terminal emulation).

    The shell channel is obviously used by SSH terminal clients (like OpenSSH ssh or PuTTY), under normal circumstances.

    The shell channel is a black box with an input and output. The input and output have no structure. If you for example execute a command by sending it to the input, you will never be able to tell when it ended. If you send two commands to input queue, you won't be able to distinguish what output comes from what command.

  • The exec command takes a command as an "argument" and executes it in an isolated environment – still via user's default shell, but not as a "login" shell, what may cause significant differences in the command execution.

    For a typical example of such difference, see Some Unix commands fail with "<command> not found", when executed using Python Paramiko exec_command.

    The purpose of the exec channel is automating a command execution. So typically you do not want to use a terminal emulation, to avoid the command to do fancy stuff like pagination, coloring and mainly interactive confirmations. That's why the default value of get_pty is False.

    The exec channel is used by OpenSSH ssh or PuTTY plink, when you specify a command to execute on its command line:

    ssh user@host command

With less common SSH servers, the difference can be even more significant. Some servers may even not support one of the channels. It is also quite common that they seemingly support both, but one of them (typically the exec) is completely broken.

See Executing command using Paramiko exec_command on device is not working.


There's a similar question for Java/JSch:

What is the difference between the 'shell' channel and the 'exec' channel in JSch

Implementing SSH shell terminal in webapp using JSch

If you want to implement an interactive shell, you have to use the "shell" channel, not the "exec" channel. The "exec" channel is intended for automating individual commands.

Some references:

  • What is the difference between the 'shell' channel and the 'exec' channel in JSch
  • JSch Shell.java example

Executing sudo using SSH exec channel in JSch

Your code executes each command in an isolated environment. So your second whoami does not run within pbrun su, as you probably hoped for.

The pbrun su executes a new shell.

To provide a command to the shell you either:

  • specify the command on su command-line, like the official JSch Sudo.java example shows:

    ((ChannelExec)channel).setCommand("pbrun su - fclaim -c whoami");
  • or feed the command to the shell using its standard input:

    OutputStream out = channel.getOutputStream();
    out.write(("whoami\n").getBytes());

    See also:

    Executing multiple bash commands using a Java JSch program after sudo login and

    Running command after sudo login.

In general, I recommend the first approach as it uses a better defined API (command-line argument).

JSch Channel.getExitStatus does not return status of command executed in shell channel

Do not execute commands in "shell" channel in the first place. The "shell" is a black box with an input and output only. See What is the difference between the 'shell' channel and the 'exec' channel in JSch

Use the "exec" channel. In the "exec" channel, the Channel.getExitStatus works.

For a code example, see: How to read JSch command output?


Obligatory warning: Do not use StrictHostKeyChecking=no to blindly accept all host keys. That is a security flaw. You lose a protection against MITM attacks. For the correct (and secure) approach, see: How to resolve Java UnknownHostKey, while using JSch SFTP library?



Related Topics



Leave a reply



Submit