JSch中'shell'通道和'exec'通道之间有什么区别?

Mar*_*osi 28 java ssh jsch

我希望能够将Java应用程序中表示为字符串的许多连续命令发送到SSH服务器以供执行.我应该使用:

Channel channel = session.openChannel("shell");
Run Code Online (Sandbox Code Playgroud)

-要么-

Channel channel = session.openChannel("exec");
Run Code Online (Sandbox Code Playgroud)

Eug*_*its 16

使用shell通道shell(在unix上sh或bash或类似的东西,在Windows上它通常是cmd.exe)启动并创建控制台(如果你在本地运行它们就会在屏幕上看到).您有一个提示,您可以解析或用于检测命令的完成.

使用命令通道,为每个命令启动一个shell实例(实际上为每个命令打开通道),并且命令作为shell的参数传递(在Windows上它看起来像"cmd.exe/c").

使用命令通道更容易,因为您不需要处理命令提示符.

  • 它可以使用`&`来完成windows(即在linux上的`;`的效果相同).可以在这里找到更多的信息(`&&`,`||`,`()`)https://www.google.com.eg/search?q=cmd+multiple+commands&sugexp=chrome,mod=0&sourceid=铬&即= UTF-8 (2认同)

Paŭ*_*ann 15

有关这些流之间的差异和相似之处的概述,您可以在JSch wiki中的Shell,Exec或Subsystem Channel «中找到它们.这里有一些用例的详细信息.

exec通道中,命令来自您给出的命令字符串setCommand().SSH服务器会立即将它们传递给shell(使用类似的东西bash -c '<command>').

如果由于某种原因shell没有以某种方式退出,它们都将被执行.(你可以在这里发送一个完整的shell脚本if,如果需要的话,可以实现一些使用和类似的逻辑.)

因此,要执行多个命令,可以通过用;newline(\n)分隔它们将它们传递给exec通道.因为你不能在给出所有命令之前等待结果,所以在这里你只能使用多个exec通道(但是当每个通道产生一个新的shell时,它们不会保存它们之间的状态,比如工作目录或shell变量).

shell通道中,shell将从流中读取输入,并将第一行解释为命令(或多个命令).

然后它将执行此命令.如果需要,命令本身可能会从流中读取更多输入.

然后shell将读取下一行,将其解释为命令,然后执行.

(在某些情况下,shell必须读取多行,例如对于长字符串或组合命令,如if或loops.)

这将一直持续到流的末尾(例如,您身边的stream.close())或执行显式退出命令.

如果您没有通过通道输入/输出流向shell发送任何输入,那么shell将等待您发送更多或关闭流.因此,您可以安静地读取一个命令的输出,在客户端进行一些计算,然后决定下一个要发送的命令.

只要确保不要将输入混合到一个命令和下一个命令的文本 - 最好不要使用任何从标准输入读取的命令.


Mar*_*osi 6

好吧,我发现这是有效的,如果你想像常规shell一样保存状态会非常方便:

Session session = jsch.getSession(user, host, 22);

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

OutputStream inputstream_for_the_channel = channel.getOutputStream();
PrintStream commander = new PrintStream(inputstream_for_the_channel, true);

channel.setOutputStream(System.out, true);

channel.connect();

commander.println("ls -la");    
commander.println("cd folder");
commander.println("ls -la");
commander.println("exit");
commander.close();

do {
    Thread.sleep(1000);
} while(!channel.isEOF());

session.disconnect();
Run Code Online (Sandbox Code Playgroud)

你可以改变

channel.setOutputStream(System.out, true);
Run Code Online (Sandbox Code Playgroud)

InputStream outputstream_from_the_channel = channel.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(outputstream_from_the_channel));
String line;
while ((line = br.readLine()) != null)
    System.out.print(line+"\n");
Run Code Online (Sandbox Code Playgroud)

如果你想要更多的输出控制.

================================================== ===========================

编辑:跟进

为什么有时我通过PrintStream发送的命令会随机出现在输出中.即以下代码:

shell[0].println("cd ..");
shell[0].println("cd ..");
shell[0].println("ls -la");
shell[0].println("exit");
Run Code Online (Sandbox Code Playgroud)

产生这个:(用{thing}标记的东西不应该存在!)

上次登录时间:2011年7月21日星期一21:49:13来自网关

清单:trunk-latest

[host~] $ cd ..
{cd ..} [host home] $
[host home] $ cd ..
[host /] $
[host /] $ ls -la
{exit}

总计9999
---------- 27 root root 4096 2010年1月26日.
---------- 27 root root 4096 2010年
1 月26日.. ---------- 1 root root 0 Mar 14 19:16 .autojyk
---------- 1 root root 0 2009年2月9日.automan
---------- 1 root root 3550 2010年5月14日.bash_history
d --------- 2 root root 4096 Apr 26 04:02 put
d- -------- 5 root root 4024 Apr 25 19:31 boot
[m [host /] $
[host /] $ exit
logout


Mar*_*ryl 5

这与 JSch 无关。这是关于服务器如何实现两个通道。


常见的 *nix OpenSSH 服务器:

  • shell信道执行一个登录shell(如如果用SSH终端客户机登录)。然后 shell 将显示命令提示符并等待客户端/用户键入命令。shell通道的目的是实现交互式 shell 会话。这是人们很少会做的事情。如果这样做,您通常希望使用终端仿真。

    在正常情况下,该shell通道显然由 SSH 终端客户端(如 OpenSSHssh或 PuTTY)使用。

    shell信道是一个黑盒子具有输入和输出。输入和输出没有结构。例如,如果您通过将命令发送到输入来执行命令,您将永远无法知道它何时结束。如果您向输入队列发送两个命令,您将无法区分什么输出来自什么命令。

  • exec命令将命令作为“参数”并在隔离环境中执行——仍然通过用户的默认 shell,但不是作为“登录”shell,这可能会导致命令执行的显着差异。

    exec通道的目的是自动执行命令。所以通常你不想使用终端模拟,以避免命令做一些花哨的事情,比如分页、着色和主要是交互式确认。

    exec当您指定要在其命令行上执行的命令时,通道由 OpenSSHssh或 PuTTY使用plink

    ssh user@host command
    
    Run Code Online (Sandbox Code Playgroud)

对于不太常见的 SSH 服务器,差异可能更大。某些服务器甚至可能不支持其中一个频道。它们似乎同时支持两者也很常见,但其中一个(通常是exec)已完全损坏。


Python/ Paramiko有一个类似的问题:
Paramiko 上的 exec_command 和使用 invoke_shell() 发送有什么区别?