通过JSch在Java上运行Linux命令

Mig*_*gel 4 java linux ssh command jsch

我正在通过Java上的JSch建立ssh连接,在我尝试运行此.sh文件之前,一切似乎都工作正常。外壳程序脚本的名称是repoUpdate.sh,非常简单:

echo  ' ****Repository update****'
echo  ' Location: /home/cissys/repo/'
echo -e ' Command: svn update /home/cissys/repo/2.3.0'

svn update /home/cissys/repo/2.3.0
Run Code Online (Sandbox Code Playgroud)

这是我通过适当的命令响应直接在linux控制台上获得的输出:

[cissys@dsatelnx5 ~]$ repoUpdate.sh
 ****Repository update****
 Location: /home/cissys/repo/
 Command: svn update /home/cissys/repo/2.3.0

At revision 9432.
Run Code Online (Sandbox Code Playgroud)

现在,这是我的带有ssh连接的方法的Java代码,该代码试图调用同一文件

public void cmremove()
{
    try
    {
        JSch jsch = new JSch();
        Session session = jsch.getSession(user, host, port);
        UserInfo ui = new SUserInfo(pass, null);
        session.setUserInfo(ui);
        session.setPassword(pass);
        session.connect();

        ChannelExec channelExec = (ChannelExec)session.openChannel("exec");

        InputStream in = channelExec.getInputStream();

        channelExec.setCommand("./repoUpdate.sh");
        channelExec.connect();

        BufferedReader reader = new BufferedReader(new InputStreamReader(in));
        String line;
        int index = 0;

        while ((line = reader.readLine()) != null)
        {
            System.out.println(++index + " : " + line);
        }

        channelExec.disconnect();
        session.disconnect();

        System.out.println("Done!");
    }
    catch(Exception e)
    {
        System.err.println("Error: " + e);
    }
}
Run Code Online (Sandbox Code Playgroud)

我得到的答复如下:

run:
1 :  ****Repository update****
2 :  Location: /home/cissys/repo/
3 :  Command: svn update /home/cissys/repo/2.3.0
Done!
BUILD SUCCESSFUL (total time: 2 seconds)
Run Code Online (Sandbox Code Playgroud)

svn命令(修订版9432)无任何输出或执行的迹象。

我认为这可能会在某个时候关闭会话,而不是让命令正确执行。如果updateRepo.sh文件具有“ cp test.txt test_2.txt”之类的东西,它将毫无问题。但是我对此和其他一些特定的.sh文件只有这个问题。

任何帮助,将不胜感激。

Dan*_*tin 5

我怀疑您的shell命令由于某种原因svn而出错-也许不在您的路径上,也许还有其他怪异的环境影响-但是您没有得到错误输出,因为您没有在寻找它。通常,错误是在您从中获取的流上发送的,channelExec.getErrStream但是在代码中,您只能从getOutputStream流中读取。

为了诊断这一点,您将需要获取这些错误消息。让linux将一个流同时用于常规输出和错误消息可能比让Java程序一次从两个流中提取要容易得多,因此我将以下行添加为repoUpdate.sh

exec 2>&1
Run Code Online (Sandbox Code Playgroud)

然后,这将导致脚本的其余部分使用您正在读取的一个流作为输出和错误。

同样,在调用之前chanelExec.disconnect,应在Java程序中记录退出状态,然后更改“完成!”。基于以下内容的消息:

    int exitStatus = channelExec.getExitStatus();
    channelExec.disconnect();
    session.disconnect();

    if (exitStatus < 0) {
        System.out.println("Done, but exit status not set!");
    } else if (exitStatus > 0) {
        System.out.println("Done, but with error!");
    } else {
        System.out.println("Done!");
    }
Run Code Online (Sandbox Code Playgroud)

如果执行此操作,则应该收到错误消息,告诉您为什么命令无法按预期运行。


Mig*_*gel 5

这就是我所做的。
exec 2>&1repoUpdate.sh文件的顶部添加了,并添加了这段代码以按@DanielMartin的建议读取输出错误,结果是:

public void cmremove()
{
    try
    {
        JSch jsch = new JSch();
        Session session = jsch.getSession(user, host, port);
        UserInfo ui = new SUserInfo(pass, null);
        session.setUserInfo(ui);
        session.setPassword(pass);
        session.connect();

        ChannelExec channelExec = (ChannelExec)session.openChannel("exec");

        InputStream in = channelExec.getInputStream();

        channelExec.setCommand("./repoUpdate.sh");
        channelExec.connect();

        BufferedReader reader = new BufferedReader(new InputStreamReader(in));
        String line;
        int index = 0;

        while ((line = reader.readLine()) != null)
        {
            System.out.println(++index + " : " + line);
        }

        int exitStatus = channelExec.getExitStatus();
        channelExec.disconnect();
        session.disconnect();
        if(exitStatus < 0){
            System.out.println("Done, but exit status not set!");
        }
        else if(exitStatus > 0){
            System.out.println("Done, but with error!");
        }
        else{
            System.out.println("Done!");
        }
    }
    catch(Exception e)
    {
        System.err.println("Error: " + e);
    }
}
Run Code Online (Sandbox Code Playgroud)

因此,实际上起到了很大作用。它确认命令实际上没有按照我的想法正确执行。我在我的java输出中得到了这个:

run:
1 :  ****Repository update****
2 :  Location: /home/cissys/repo/
3 :  Command: svn update /home/cissys/repo/2.3.0
4 : ./repoUpdate.sh[6]: svn: not found [No such file or directory]
Done!
BUILD SUCCESSFUL (total time: 2 seconds)
Run Code Online (Sandbox Code Playgroud)

然后我尝试修改repoUpdate.sh文件,为svn命令添加绝对路径(谢谢,@ ymnk)

exec 2>&1
echo  ' ****Repository update****'
echo  ' Location: /home/cissys/repo/'
echo -e ' Command: svn update /home/cissys/repo/2.3.0'

/opt/subversion/bin/svn update /home/cissys/repo/2.3.0
Run Code Online (Sandbox Code Playgroud)

对于我的Java,我得到了我想要的东西:

run:
1 :  ****Repository update****
2 :  Location: /home/cissys/repo/
3 :  Command: svn update /home/cissys/repo/2.3.0
4 : At revision 9443.
Done!
BUILD SUCCESSFUL (total time: 3 seconds)
Run Code Online (Sandbox Code Playgroud)

我发现$PATH通过java从会话中获得的与直接从linux控制台获得的是不同的。因此,添加svn路径实际上可以解决问题。非常感谢您的帮助!