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

时间:2011-07-21 00:49:03

标签: java ssh jsch

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

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

-OR -

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

4 个答案:

答案 0 :(得分:15)

您可以在JSch wiki中的»Shell, Exec or Subsystem Channel«找到这些流之间的差异和相似之处。这里有一些用例的详细信息。

exec channel中,命令来自您使用setCommand()提供的命令字符串。 SSH服务器会立即将它们传递给shell(使用bash -c '<command>')。

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

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

shell channel中,shell将从流中读取输入,并将第一行解释为命令(或几个)。

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

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

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

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

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

请确保不要将输入与一个命令混合使用下一个命令的文本 - 最好不要使用任何可从标准输入读取的命令。

答案 1 :(得分:15)

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

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

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

答案 2 :(得分: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();

你可以改变

channel.setOutputStream(System.out, true);

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");

如果你想要更多控制输出。

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

编辑:跟进

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

shell[0].println("cd ..");
shell[0].println("cd ..");
shell[0].println("ls -la");
shell[0].println("exit");

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

  

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

     

清单:trunk-latest

     

[host~] $ cd ..
  {cd ..} [寄宿家庭] $
  [主页] $ cd ..
  [主持人/] $
  [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
  注销

答案 3 :(得分:0)

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


常见的* nix OpenSSH服务器:

  • shell通道执行登录外壳程序(就像您使用SSH终端客户端登录一样)。然后,外壳程序将显示命令提示符,并等待客户端/用户键入命令。 shell通道的目的是实现交互式Shell会话。那是很少做的事情。如果这样做,通常需要使用终端仿真。

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

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

  • exec命令将命令作为“参数”并在隔离的环境中执行-仍然通过用户的默认外壳程序,而不是作为“登录”外壳程序,这可能会导致命令执行。

    exec通道的目的是使命令执行自动化。因此,通常您不想使用终端仿真,以避免使用该命令执行诸如分页,着色和主要是交互式确认之类的花哨的事情。

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

    ssh user@host command
    

使用不太常见的SSH服务器,两者之间的差异会更大。某些服务器甚至可能不支持其中一个通道。他们似乎同时支持这两者也是很常见的,但是其中之一(通常为exec)已被破坏。


Python / Paramiko也有类似的问题:
What is the difference between exec_command and send with invoke_shell() on Paramiko?