Multiple commands through JSch shell

Piyush picture Piyush · Apr 29, 2011 · Viewed 27.1k times · Source

I was trying to execute multiple commands through SSH protocol using the JSch library. But I seem to have stuck and cannot find any solution. The setCommand() method can only execute single commands per session. But I want to execute the commands sequentially just like the connectbot app on the Android platform. So far my code is:

package com.example.ssh;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Properties;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import com.jcraft.jsch.Channel;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;

public class ExampleSSH extends Activity {
    /** Called when the activity is first created. */
    EditText command;
    TextView result;
    Session session;
    ByteArrayOutputStream baos;
    ByteArrayInputStream bais;
    Channel channel;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        bais = new ByteArrayInputStream(new byte[1000]);
        command = (EditText) findViewById(R.id.editText1);
        result  = (TextView) findViewById(R.id.terminal);
    }

    public void onSSH(View v){
        String username = "xxxyyyzzz";
        String password = "aaabbbccc";
        String host     = "192.168.1.1"; // sample ip address
        if(command.getText().toString() != ""){
            JSch jsch = new JSch();
            try {
                session = jsch.getSession(username, host, 22);
                session.setPassword(password);

                Properties properties = new Properties();
                properties.put("StrictHostKeyChecking", "no");
                session.setConfig(properties);
                session.connect(30000);

                channel = session.openChannel("shell");
                channel.setInputStream(bais);
                channel.setOutputStream(baos);
                channel.connect();

            } catch (JSchException e) {
                // TODO Auto-generated catch block
                Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show();
            }
        }
        else{
            Toast.makeText(this, "Command cannot be empty !", Toast.LENGTH_LONG).show();
        }
    }

    public void onCommand(View v){
        try {
            bais.read(command.getText().toString().getBytes());
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        baos = new ByteArrayOutputStream();
        channel.setOutputStream(baos);
        result.setText(baos.toString());

    }
}

The code seems to get connected to the server but I think there is some problem with the input and output array buffers because there is no output at all. Can someone please guide me how to handle the input and output to and from the server properly to get the desired output?

Answer

Aaron Digulla picture Aaron Digulla · Apr 29, 2011

The command is a String and can be anything the remote shell accepts. Try

cmd1 ; cmd2 ; cmd3

to run several commands in sequence. Or

cmd1 && cmd2 && cmd3

to run commands until one fails.

Even this might work:

cmd1
cmd2
cmd3

or in Java:

channel.setCommand("cmd1\ncmd2\ncmd3");

Sidenote: Don't put passwords and user names into the code. Put them into a property file and use a system property to specify the name of the property file. That way, you can keep the file even outside the project and make sure passwords/user names don't leak.