JSch Shell channel execute commands one by one tes

2020-02-06 05:23发布

问题:

I have a program for connecting to a SSH shell. I was able to execute the commands and read output from it.

But I have a new requirement. Now I need to execute a command and read output if successful execute the next command.

I have used the program from this question: JSch issue - Cannot retrieve full command output

public class SshConnectionManager {

    private static Session session;
    private static ChannelShell channel;
    private static String username = "";
    private static String password = "";
    private static String hostname = "";


    private static Session getSession(){
        if(session == null || !session.isConnected()){
            session = connect(hostname,username,password);
        }
        return session;
    }

    private static Channel getChannel(){
        if(channel == null || !channel.isConnected()){
            try{
                channel = (ChannelShell)getSession().openChannel("shell");
                channel.setPty(false);
                channel.connect();

            }catch(Exception e){
                System.out.println("Error while opening channel: "+ e);
            }
        }
        return channel;
    }

    private static Session connect(String hostname, String username, String password){

        JSch jSch = new JSch();

        try {

            session = jSch.getSession(username, hostname, 22);
            Properties config = new Properties(); 
            config.put("StrictHostKeyChecking", "no");
            session.setConfig(config);
            session.setPassword(password);

            System.out.println("Connecting SSH to " + hostname + " - Please wait for few seconds... ");
            session.connect();
            System.out.println("Connected!");
        }catch(Exception e){
            System.out.println("An error occurred while connecting to "+hostname+": "+e);
        }

        return session;

    }

    private static void executeCommands(List<String> commands){

        try{
            Channel channel=getChannel();

            System.out.println("Sending commands...");
            sendCommands(channel, commands);

            readChannelOutput(channel);
            System.out.println("Finished sending commands!");

        }catch(Exception e){
            System.out.println("An error ocurred during executeCommands: "+e);
        }
    }

    private static void sendCommands(Channel channel, List<String> commands){

        try{
            PrintStream out = new PrintStream(channel.getOutputStream());

            out.println("#!/bin/bash");
            for(String command : commands){
                out.println(command);
            }
            out.println("exit");

            out.flush();
        }catch(Exception e){
            System.out.println("Error while sending commands: "+ e);
        }

    }

    private static void readChannelOutput(Channel channel){

        byte[] buffer = new byte[1024];

        try{
            InputStream in = channel.getInputStream();
            String line = "";
            while (true){
                while (in.available() > 0) {
                    int i = in.read(buffer, 0, 1024);
                    if (i < 0) {
                        break;
                    }
                    line = new String(buffer, 0, i);
                    System.out.println(line);
                }

                if(line.contains("logout")){
                    break;
                }

                if (channel.isClosed()){
                    break;
                }
                try {
                    Thread.sleep(1000);
                } catch (Exception ee){}
            }
        }catch(Exception e){
            System.out.println("Error while reading channel output: "+ e);
        }

    }

    public static void close(){
        channel.disconnect();
        session.disconnect();
        System.out.println("Disconnected channel and session");
    }


    public static void main(String[] args){
        List<String> commands = new ArrayList<String>();
        commands.add("ls -l");

        executeCommands(commands);
        close();
    }
}

I need to use "shell" channel instead of "exec" because the server does not allow the "exec" channel: http://www.tembria.com/forums/viewtopic.php?t=477&sid=8f2a82ec30e89ba44d184a3b2a65ec69

回答1:

In general you should use an "exec" channel for this. The "shell" channel should not be used to automate a command execution.

But I understand that your server does not support the "exec" channel. I've added the above comment for the other readers, not to try to use this solution, unless they really have to.


As @Yair Harel already commented, if you have to use the "shell" channel, you have to use shell techniques.

So in your particular case, you may want to have the remote shell print some unique string and the exit code after the command finishes:

out.println(command + " ; echo Command-has-finished-with-code-$?");

Then you keep reading the output until you find a line starting "Command-has-finished-with-code-". You parse the exit code and decide how to proceed.

Note that the command syntax (particularly the command separator character ; and exit code variable $?) is OS- and shell-specific. As your server is not of a standard kind, the syntax may be different.


Side notes:

  • The "#!/bin/bash" is a pure nonsense. The shell ignores all commands starting with # (it's comment). There's no point sending it.
  • Do not use StrictHostKeyChecking=no. See JSch SFTP security with session.setConfig("StrictHostKeyChecking", "no");


标签: java ssh jsch