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
Date Object Simpledateformat Not Parsing Timestamp String Correctly in Java (Android) Environment
Android Changing Floating Action Button Color
How Can One Detect Airplane Mode on Android
How to Call JavaScript from Android
Opengl Es2 Alpha Test Problems
Gradle - What Is a Non-Zero Exit Value and How to Fix It
Android: How to Stretch an Image to the Screen Width While Maintaining Aspect Ratio
How to Make a Copy of a File in Android
Transitive Dependencies Not Resolved for Aar Library Using Gradle
Java Split() Method Strips Empty Strings at the End
MySQL and Jdbc with Rewritebatchedstatements=True
How to Add and Remove Elements of Enumeration at Runtime in Java