Running linux commands on java through JSch

2019-02-15 05:12发布

问题:

I'm establishing a ssh connection through JSch on java and everything seemed to be working fine, until I tried to run this .sh file. The shell script's name is repoUpdate.sh and it's very simple:

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

This is the output I get directly on the linux console with the proper response of the command:

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

At revision 9432.

Now, here's the java code of my method with the ssh connection that tries to call this same file

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

And the response I get is the following:

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)

with no output or signs of execution on the svn command (At revision 9432) whatsoever.

I'm thinking it may be closing the session at some point, not letting the command execute properly. If the updateRepo.sh file would've had something like "cp test.txt test_2.txt", it would do it with no problem. But i only have this problem with this and some other specific .sh files.

Any help would be appreciated.

回答1:

I suspect that your shell command is erroring out for some reason - perhaps svn isn't on your path, perhaps there are other weird environmental effects - but you're not getting the error output because you aren't looking for it. Normally, errors are sent on the stream you get from channelExec.getErrStream but in your code you only read from the getOutputStream stream.

To diagnose this, you're going to need to get those error messages. It's probably easier to get linux to use one stream for both regular output and error messages than to have your java program pulling from two streams at once, so I'd add this line as the top line of repoUpdate.sh:

exec 2>&1

That'll then cause the rest of the script to use the one stream you're reading from as both output and error.

Also, right before you call chanelExec.disconnect, in your java program you should record the exit status, and then change your "Done!" message based on what it was:

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

If you do this, you should then get error messages that tell you why your command isn't working as you expect it should.



回答2:

So here's what I did.
I added the exec 2>&1 at the top of the repoUpdate.sh file and added that piece of code to read the output error as @DanielMartin suggested, resulting on this:

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

So that actually helped a lot. It confirmed that the command was, in fact, not executing correctly as I thought. I was getting this on my java output:

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)

Then I tried modifying the repoUpdate.sh file, adding the absolute path for the svn command (Thank you, @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

For my java, I got just what I was looking for:

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)

I found out that the $PATH I get from the session through java is not the same that I get directly on the linux console. So adding the svn path actually did the trick. Thank you very much for your help!



回答3:

How about using the absolute path for 'svn' command?