使用jsch执行多个shell脚本

时间:2014-04-15 19:09:49

标签: java shell unix expect jsch

我正在使用Jsch库在少数linux机器上执行大约1000种不同的shell脚本,并将状态更新为表格。

我使用了jsch exec channel [ChannelExec],它只适用于单个脚本,如果shell脚本调用另一个脚本,则ChannelExec没有给出正确的结果。

现在我正在使用jsch的shell channnel。它可以很好地从任何类型的shell脚本中获取输出。

问题是,如果我一次执行多个shell脚本,我将获得所有结果。

无法执行一个Shell脚本并收到其结果。

如果我想获得单个脚本执行结果,我需要为每个脚本执行登录到机器,这需要很长时间。

有人可以发布解决方案,建议如何进行,登录一次机器并执行多个脚本并单独接收每个脚本结果。

import com.jcraft.jsch.Channel;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;

public class JschShellExample {

    public static void main(String[] args) {

        try {
            JSch jsch = new JSch();

            Session session = jsch.getSession("user", "10.32.248.158", 22);
            session.setPassword("password");

            java.util.Properties config = new java.util.Properties();
            config.put("StrictHostKeyChecking", "no");
            config.put("PreferredAuthentications","publickey,keyboard-interactive,password");
            session.setConfig(config);
            session.connect(100);

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

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

            channel.setOutputStream(null);
            channel.connect(100);
            //shell script
            commander.println("cd /user/home/work ; ./checkstaus.sh ; exit");
            commander.flush();

            System.out.println(channel.getExitStatus());

            InputStream outputstream_from_the_channel = channel.getInputStream();
            BufferedReader br = new BufferedReader(new InputStreamReader(outputstream_from_the_channel));
            String line = null;
            StringBuilder sb = new StringBuilder();
            boolean isloginStringPassed = false ;

            while ((line = br.readLine()) != null) {
                    sb.append(line.trim());
            }
            System.out.println("Result ="+sb.toString());

            channel.disconnect();
            session.disconnect();
            System.out.println("completed .. ");
        } catch (JSchException ex) {
            ex.printStackTrace();
        } catch (IOException ex) {
            ex.printStackTrace();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

}

1 个答案:

答案 0 :(得分:0)

通常当您第一次连接到远程计算机并执行命令后,您将在输出流中打印shell command line prompt。您可以将它用作不同shell命令输出之间的标记。

您可以考虑使用Expect-like第三方库,它简化了远程服务的工作并捕获输出。你可以尝试一系列很好的选择:

然而,当我即将解决类似的问题时,我发现这些库相当陈旧,难以在商业软件中使用。所以我创建了自己的,并将其提供给其他人。它叫ExpectIt。我的库的优点在project home page上说明。

以下是与公共远程SSH服务进行交互的示例:

    JSch jSch = new JSch();
    Session session = jSch.getSession("new", "sdf.org");
    Properties config = new Properties();
    config.put("StrictHostKeyChecking", "no");
    session.setConfig(config);
    session.connect();
    Channel channel = session.openChannel("shell");

    Expect expect = new ExpectBuilder()
            .withOutput(channel.getOutputStream())
            .withInputs(channel.getInputStream(), channel.getExtInputStream())
            .withEchoOutput(adapt(System.out))
    //        .withInputFilters(removeColors(), removeNonPrintable())
            .withErrorOnTimeout(true)
            .build();
    // try-with-resources is omitted for simplicity
    channel.connect();
    expect.expect(contains("[RETURN]"));
    expect.sendLine();
    String ipAddress = expect.expect(regexp("Trying (.*)\\.\\.\\.")).group(1);
    System.out.println("Captured IP: " + ipAddress);
    expect.expect(contains("login:"));
    expect.sendLine("new");
    expect.expect(contains("(Y/N)"));
    expect.send("N");
    expect.expect(regexp(": $"));
    // finally is omitted
    channel.disconnect();
    session.disconnect();
    expect.close();

您还可以查看一个与卡拉夫外壳交互的this示例,该外壳可捕获单个命令输出。