How to Read Jsch Command Output

How to read JSch command output?

One has to read the output continuously, while waiting for the command to finish. Otherwise, if the command produces enough output to fill in an output buffer, the command will hang, waiting for the buffer to be consumed, what never happens. So you get a deadlock.

The following example reads both stdout and stderr continuously, while monitoring a command status. It is based on the official JSch exec.java example (just adds a reading of stderr).

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

channel.setCommand(
"for((i=1;i<=10000;i+=2)); do echo \"Long output - $i\"; done ; " +
"echo error output >&2");

ByteArrayOutputStream outputBuffer = new ByteArrayOutputStream();
ByteArrayOutputStream errorBuffer = new ByteArrayOutputStream();

InputStream in = channel.getInputStream();
InputStream err = channel.getExtInputStream();

channel.connect();

byte[] tmp = new byte[1024];
while (true) {
while (in.available() > 0) {
int i = in.read(tmp, 0, 1024);
if (i < 0) break;
outputBuffer.write(tmp, 0, i);
}
while (err.available() > 0) {
int i = err.read(tmp, 0, 1024);
if (i < 0) break;
errorBuffer.write(tmp, 0, i);
}
if (channel.isClosed()) {
if ((in.available() > 0) || (err.available() > 0)) continue;
System.out.println("exit-status: " + channel.getExitStatus());
break;
}
try {
Thread.sleep(1000);
} catch (Exception ee) {
}
}

System.out.println("output: " + outputBuffer.toString("UTF-8"));
System.out.println("error: " + errorBuffer.toString("UTF-8"));

channel.disconnect();

If you add while (!channel.isClosed()) {} after the channel.connect();, you will see that with a sufficiently large i in the shell for loop (10000 is enough with in my environment), the loop never finishes.

How to get jsch shell command output in String

For 2) u can use ByteArrayOutputStream

final ByteArrayOutputStream baos = new ByteArrayOutputStream();
channel.setOutputStream(baos);

and then create new string from new String(baos.toByteArray())

For 1 have you tried to use 2>&1 at the end of your command?

String commandToRun = "ls /tmp/*.log 2>&1 \n";

How to read the output of jsch command in Android?

I changed the following section of the code, from this:

ChannelExec channel1 = (ChannelExec)session.openChannel("exec");
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
channel1.setOutputStream(baos);
channel1.setCommand("ls /home/pi/pic | sed -n 5p");
aaaa = new String(baos.toByteArray());

to this:

ChannelExec channel1 = (ChannelExec)session.openChannel("exec");
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
channel1.setOutputStream(baos);
channel1.setCommand("ls /home/pi/pic | sed -n 5p | xargs echo -n");
channel1.connect();
try{Thread.sleep(1000);}catch(Exception ee){}
aaaa = new String(baos.toByteArray());

And the problem solved.

Get output of a specific command only in JSch shell channel

You have to read the output to some buffer/string. Then parse out and print only the part you want.

See How to get jsch shell command output in String.


There's no other way to separate output of individual commands. From an SSH client perspective, the shell is just a black box with input/output. There's no structure. The "shell" should not be use to automate command execution. You should use the "exec" channel. See also What is the difference between the 'shell' channel and the 'exec' channel in JSch.

In the "exec" channel, you execute each command independently, so you won't have problems separating their output. See How to read JSch command output?


Anyway, if you want to stick with your suboptimal "shell" solution, it helps, when you print some delimiter before and after the script like:

echo ---begin---
/.../myscript.sh
echo ---end---

Capture server command output using JSch and Java

Use exec channel, not shell channel. The exec channel is intended for command execution. The shell channel is intended for implementing an interactive session. That's why you get all the prompts and such. You do not get these in the exec channel.

See the official JSCh example for using exec channel.

If you need to read both stdout and stderr, see my answer to How to read JSch command output?

How to get the Output result in jsch

this is how I read the output of my command

Edit

1) Method to Connect to the server:

public void connect (final String host){
if(host.isEmpty())
return;

hostname = host;
try{
JSch jsch=new JSch();
String user ="yourUserName";
String host = "yourHost";

Session myLocalSession=jsch.getSession(user, host, 22);
//myLocalSession=jsch.getSession(user, "192.168.1.104", 22);

myLocalSession.setPassword("yourPassword");

myLocalSession.setConfig("StrictHostKeyChecking", "no");

myLocalSession.connect(5000); // making a connection with timeout.
myChannel = myLocalSession.openChannel("shell");

InputStream inStream = myChannel.getInputStream();

OutputStream outStream = myChannel.getOutputStream();
toChannel = new PrintWriter(new OutputStreamWriter(outStream), true);

myChannel.connect();
readerThread(new InputStreamReader(inStream));

Thread.sleep(100);
sendCommand("cd "+path);
}
catch(JSchException e){
String message = e.getMessage();
if(message.contains("UnknownHostException"))
myParser.print(">>>>> Unknow Host. Please verify hostname.");
else if(message.contains("socket is not established"))
myParser.print(">>>>> Can't connect to the server for the moment.");
else if(message.contains("Auth fail"))
myParser.print(">>>>> Please verify login and password");
else if(message.contains("Connection refused"))
myParser.print(">>>>> The server refused the connection");
else
System.out.println("*******Unknown ERROR********");

System.out.println(e.getMessage());
System.out.println(e + "****connect()");
}
catch(IOException e)
{
System.out.println(e);
myParser.print(">>>>> Error when reading data streams from the server");
}
catch(Exception e){
e.printStackTrace();
}
}

2) Method to send a command to the server

public void sendCommand(final String command)
{
if(myLocalSession != null && myLocalSession.isConnected())
{
try {
toChannel.println(command);
} catch(Exception e){
e.printStackTrace();
}
}
}

3) Thread method that read answer from the server

void readerThread(final InputStreamReader tout)
{
Thread read2 = new Thread(){
@Override
public void run(){
StringBuilder line = new StringBuilder();
char toAppend = ' ';
try {
while(true){
try {
while (tout.ready()) {
toAppend = (char) tout.read();
if(toAppend == '\n')
{
System.out.print(line.toString());
line.setLength(0);
}
else
line.append(toAppend);
}
} catch (Exception e) {
e.printStackTrace();
System.out.println("\n\n\n************errorrrrrrr reading character**********\n\n\n");
}
Thread.sleep(1000);
}
}catch (Exception ex) {
System.out.println(ex);
try{
tout.close();
}
catch(Exception e)
{}
}
}
};
read2.start();
}

You can use a bufferedReader with the InputStreamReader and read line by line. I use an infinite loop and pause for one second after each failed attempt to read (nothing from the server).

Let's say that the three method are in SessionB class. Example:

SessionB testConnexion = new SessionB();
testConnexion.connect();
testConnexion.sendCommand("cd myFolder");
testConnexion.sendCommand("ls");

You should get the list of file in your console.

If you need, to be able to interact (send a command depending of the output), check my post here.

JSch exec sudo command : How to access sudo command output text?

Using @MartinPrikil's solution How to read JSch command output? (But this solution has an infinite loop)

I took some of his code and added it to my code as follows: This gives me programmatic access to the error text via the variable "errorBufferedReader"

   ((ChannelExec(channel).setCommand(command);
channel.setInputStream(null);
((ChannelExec(channel).setErrStream(System.err);
InputStream input = channel.getInputStream();
InputStream error = channel.getExtInputStream();
channel.connect();
List<String> output = new ArrayList<>();
List<String> errorOutput = new ArrayList<>();

try {
InputStreamReader inputReader = new InputStreamReader(input);
BufferedReader bufferedReader = new BufferedReader(inputReader);
InputStreamReader errorReader = new InputStreamReader(error);
BufferedReader errorBufferedReader = new BufferedReader(errorReader);
String line = null;
while (true) {
while ((line = bufferedReader.readLine()) != null) {
output.add(line);
System.out.println("here is a line " + line);
}
while ((line = errorBufferedReader.readLine()) != null) {
Output.add(line);
System.out.println("here is an error line " + line);
}
if (channel.isClosed()( { etc etc }

JSch Channel.getExitStatus does not return status of command executed in shell channel

Do not execute commands in "shell" channel in the first place. The "shell" is a black box with an input and output only. See What is the difference between the 'shell' channel and the 'exec' channel in JSch

Use the "exec" channel. In the "exec" channel, the Channel.getExitStatus works.

For a code example, see: How to read JSch command output?


Obligatory warning: Do not use StrictHostKeyChecking=no to blindly accept all host keys. That is a security flaw. You lose a protection against MITM attacks. For the correct (and secure) approach, see: How to resolve Java UnknownHostKey, while using JSch SFTP library?



Related Topics



Leave a reply



Submit