有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

通过SSH命令执行java远程脚本:如何知道是否正确执行

我需要通过SSH和Java执行Linux脚本,该脚本驻留在远程Linux机器上。 在运行时,我从DB中检索脚本的名称、主机和凭据,并尝试通过ssh启动脚本。这是好的,因为我得到了执行PID作为回报! 问题是我总是得到一个执行的PID,即使脚本是错误的,或者它不存在,或者它没有执行权限

有没有办法知道执行是否正确或命令是否错误?我需要知道是否可以在同一个ssh启动命令中使用。先谢谢你

我们使用的代码如下所示:

   JSch jsch = new JSch();
String post_process_host="123.123.123.123";
Integer post_process_port=22;
String post_process_user="therock";
String post_process_pwd="XxXdfG$L";
//String command="testpp.sh";
String command="./export/home/therock/test/hello.bsh";


command=command + " > /dev/null 2>&1 & \n echo $!";
Session session = jsch.getSession(post_process_user, post_process_host, post_process_port.intValue());

UserInfo ui = new SUserInfo(post_process_pwd, null);
session.setUserInfo(ui);
session.setPassword(post_process_pwd);

session.connect();


int timeout=10; //timeout di 5 minuti
StringBuffer text = new StringBuffer();
int exitCode = -1;
try {

    logger.info("Execution command: " + command);

    Channel channel = session.openChannel("exec");
    ((ChannelExec) channel).setCommand(command);
    channel.setInputStream(null);
    ((ChannelExec) channel).setErrStream(System.err);
    InputStream in = channel.getInputStream();
    InputStream err = ((ChannelExec) channel).getErrStream();
    channel.connect(timeout);
    byte[] tmp = new byte[1024];
    while (true) {
      timeout--;
      while (in.available() > 0) {
        int i = in.read(tmp, 0, 1024);
        if (i < 0)
          break;
        String line = new String(tmp, 0, i, StandardCharsets.UTF_8);
        text.append(line);
        if (text.toString().contains("\n")) break;
      }
      while (err.available() > 0) {
        int i = err.read(tmp, 0, 1024);
        if (i < 0)
          break;
        String line = new String(tmp, 0, i, StandardCharsets.UTF_8);
        text.append(line);
      }
      if (channel.isClosed()) {
        if (in.available() > 0)
          continue;
        exitCode = channel.getExitStatus();
        logger.info("Eseguito comando codice di ritorno: " + exitCode);
        logger.debug("output comando: "+text.toString());
        if (exitCode!=0) throw new Exception("Execution Command "+command+" error with Return Code="+exitCode);
        break;
      }
      try {
        Thread.sleep(1000);
      } catch (Exception ee) {
        throw ee;
      }
    }

    channel.disconnect();
  } catch (Exception e) {
    throw e;
  }
logger.debug("output command: "+text.toString());

共 (1) 个答案

  1. # 1 楼答案

    上面代码的突出部分在这2行:

    String command="./export/home/therock/test/hello.bsh";
    command=command + " > /dev/null 2>&1 & \n echo $!";
    

    它生成了一个具有以下值的command变量:

    ./export/home/therock/test/hello.bsh > /dev/null 2>&1 & \n echo $!
    

    要了解此命令的作用,您可能需要学习bash,但下面是我的快速解释:

    • 在名为./export/home/therock/test/hello.bsh的文件中执行一个命令(从扩展名来看,我假设它是一个shell脚本)
    • > /dev/null=然后将其STDOUT重定向到/dev/null(又名:放弃输出)
    • 2>&1=然后将它的STDERR重定向到STDOUT去的任何地方(如上所述,它去了/dev/null或被丢弃)
    • &=在后台执行它
    • \n echo $!=然后回显(在标准输出中打印)生成的后台进程的PID(进程id)

    现在我不知道./export/home/therock/test/hello.bsh文件的内容,但是如果它写得很好,那么它应该返回一个退出代码,指示它是否成功运行(例如:使用exit 0表示成功运行,exit 1表示失败运行,exit 2表示其他类型的错误)

    之后,我们可以通过echo $?看到最后一个命令的退出代码

    因此,您可能希望将代码重写为:

    String command="./export/home/therock/test/hello.bsh > /dev/null 2>&1 ; \n echo $?";
    

    说明:

    • 在名为./export/home/therock/test/hello.bsh的文件中执行一个命令(从扩展名来看,我假设它是一个shell脚本)
    • > /dev/null=然后将其STDOUT重定向到/dev/null(又名:放弃输出)
    • 2>&1=然后将它的STDERR重定向到STDOUT去的任何地方(如上所述,它去了/dev/null或被丢弃)
    • ;=执行完此命令后,执行下一个命令
    • \n echo $?=然后回显(在标准输出中打印)最后一个命令的退出代码

    请注意,在进行此更改之后,您将没有进程的PID,而是有退出代码。这一更改也会使java程序等待bash脚本完成

    因此,如果bash脚本运行5分钟,并且您在08:00:00开始执行java程序

    • 以前,java程序应该在08:00:01左右完成(非常快,因为它不等待bash脚本完成)
    • 更改后,java程序将在08:05:01左右完成(因为它在退出之前等待bash脚本完成)

    编辑:

    奥普说

    The business requirements are to launch a script in a remote machine in background, so I can't wait for the complete execution of the script. My personal solution is to get the PID at SSH launch time and then make another inquiry to the remote system

    您始终可以将退出代码保存到文件中,然后稍后读取该文件,例如:

    ./export/home/therock/test/hello.bsh中,您可以不写exit 0exit 1,而是写

    echo 0 >> ./export/home/therock/test/result.txt
    exit 0
    

    稍后,当您想要检查结果时,您只需要读取./export/home/therock/test/result.txt的最后一行(例如:tail -n1 ./export/home/therock/test/result.txt

    编辑2:

    OP说他/她需要知道这个过程是否已经完成

    简单的方法是创建一个锁文件(或反向锁文件)

    ./export/home/therock/test/hello.bsh的开头添加:

    rm -f ./export/home/therock/test/result.txt
    

    然后,不用写exit 0exit 1,而是可以写

    echo 0 > ./export/home/therock/test/result.txt
    exit 0
    

    因此,您知道,如果文件./export/home/therock/test/result.txt不存在,bash脚本仍在运行。如果文件存在,则表示bash脚本已完成,您可以读取其内容以查看其结果

    另一种方法(更推荐)是编写一个锁文件,该文件在bash脚本进程启动时创建,退出时删除。这样还可以确保bash脚本一次只执行一次