Converting interactive shell output to plain text - java

I am trying to view the temperature table for my CPU on my Linux machine with Java. This bit of code will display the shell output for other commands, ls, cat file, but will not display watch sensors as it returns an interactive output. Is there a way I can convert it to plain text somehow?
Error: [/usr/bin/watch, sensors]
Error opening terminal: unknown.
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
public class tempapp{
public static void main (String args[]) throws IOException, InterruptedException {
//build command
List<String> commands = new ArrayList<String>();
commands.add("/usr/bin/watch");
//args
commands.add("sensors");
System.out.println(commands);
ProcessBuilder pb = new ProcessBuilder(commands);
pb.directory(new File("/home/ethano"));
pb.redirectErrorStream(true);
Process process = pb.start();
//Read output
StringBuilder out = new StringBuilder();
BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = null, previous = null;
while ((line = br.readLine()) != null)
if (!line.equals(previous)) {
previous = line;
out.append(line).append('\n');
System.out.println(line);
}
//Check result
if (process.waitFor() == 0){
System.out.println("\n success");
System.exit(0);
}
//weird termination
System.err.println(commands);
System.err.println(out.toString());
System.exit(1);
}
}

All that watch does is call the command it is given (sensors in this case) once every two seconds. You can simply have your application emulate this behaviour by calling /usr/bin/sensors in a for-loop once every two seconds (or however many times you need), therefore omitting the need to read interactive shell output.

Related

Java enter command to a process that opens a new telnet connection

I would like to write a Java program to control the Android emulator to do some testing, and now I have to take snapshots of the emulator when it is created and every time it has changes, so according to google, the command is like:
telnet localhost 5555
Trying ::1...
Connected to localhost.
Escape character is '^]'.
Android Console: type 'help' for a list of commands
OK
avd snapshot save 1
OK
So basically two commands, the first is to open a telnet connection and then enter avd snapshot save x command to save the snapshot.
However using the command like this:
public static void main(String[] args) throws IOException{
int initScore = 1000;
int ID = 0;
// monitor the log, check if a new activity is reached.
// if so, take a snapshot of the current activity and save it to the snapshot folder.
String cmd1 = "telnet localhost " + 5555;
// the static port 5557 should change to this.getVM_consolePort();
String cmd2 = "avd snapshot save " + ID;
ProcessBuilder pb = new ProcessBuilder("/bin/sh", "-c", cmd1, cmd2);
Process p = pb.start();
// read the process output
BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
String s = null;
while ((s = stdInput.readLine()) != null) {
System.out.println(s);
}
}
can only run the first command (which is to open telnet connection).
So could anyone tell me how to interact with a opened connection or enter command to another process in Java?
Here's an example using grep:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Writer;
public class Test {
public static void main(String[] args) throws IOException {
ProcessBuilder pb = new ProcessBuilder("/bin/sh", "-c", "grep foo");
Process p = pb.start();
BufferedReader stdOut = new BufferedReader(new InputStreamReader(p.getInputStream()));
BufferedReader stdErr = new BufferedReader(new InputStreamReader(p.getErrorStream()));
Writer stdIn = new OutputStreamWriter(p.getOutputStream());
stdIn.write("foo1\nbar\nfoo2\n");
stdIn.close();
String s = null;
while ((s = stdOut.readLine()) != null) {
System.out.println(s);
}
while ((s = stdErr.readLine()) != null) {
System.out.println(s);
}
}
}
I renamed stdIn to stdOut, so they are named from the point of view of the process you're running.
I read from stderr, so that you can see any problems.
Actually I have tried this before like the code below:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.BufferedWriter;
public class Main {
public static void main(String[] args) throws IOException {
// int initScore = 1000;
int ID = 0;
Process p = Runtime.getRuntime().exec("telnet localhost 5555");
BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
BufferedWriter stdIn = new BufferedWriter(new OutputStreamWriter(p.getOutputStream()));
String line;
while ((line = stdInput.readLine()) != null) {
System.out.println(line);
if (line.contains("OK")){
break;
}
}
stdIn.write("avd snapshot save " + ID);
while ((line = stdInput.readLine()) != null) {
System.out.println(line);
}
}
}
Trying ::1...
Connected to localhost.
Escape character is '^]'.
Android Console: type 'help' for a list of commands
OK
I think the reason is that the telnet created a new shell and the writer is writing to the old shell, therefore it is not working, so I am looking for a solution to enter the new command into the new shell.

Is it possible to run cmd through a java program [duplicate]

This question already has answers here:
Start CMD by using ProcessBuilder
(3 answers)
Closed 9 years ago.
I would like to know if its possible to run cmd through Java. Not just one command at a time but a continuous stream of user input commands that relays the info received. Is this possible or should I just stop trying now?
I'm not sure why I'm attaching this; it's not very relevant, but this is what I was trying to accomplish this with. However, it resets the cmd after every command. (Yes, I realize this is bad coding, but I'm just attempting something my boss asked about.)
import java.io.*;
import java.util.Scanner;
public class Cmd {
public static void main(String[] args) throws IOException {
String line;
while (true) {
Scanner scanner = new Scanner(System.in);
String comm = scanner.nextLine();
ProcessBuilder builder = new ProcessBuilder("cmd.exe", "/c", comm);
builder.redirectErrorStream(true);
Process p = builder.start();
BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream()));
while (true) {
line = r.readLine();
if(line==null){break;}
System.out.println(line);
}
}
}
}
Basically, cmd but behind a Java GUI with user input commands is my end game. If anyone could tell me if this is possible and if so point me in the right direction I would be grateful.
Yes, it is possible.
At the end of my answer is an example program. It is far from perfect and is missing some implementation details. For example proper exception handling and also detect when the cmd has exited... But it may be used as a starting point.
In essence the solution to your question is to start cmd.exe as a new Process. Then read commands in java from standard input stream (System.in) and pipe it to the cmd.exe-process. To provide feedback to the user you must read the standard output from cmd.exe-process and print it to the standard output of your java process (System.out). Also read standard error from cmd.exe-process and print it to standard error of your java process (System.err).
Close all resources when you are done. I indicated this in the example, but this is not production ready. Any exception would prevent the example program from cleaning up.
Another implementation detail: The example program uses a second thread to read output from cmd.exe-process. Otherwise you will only get output when the user hits enter.
Finally, here is the code:
package com.example;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
public class JavaCmd {
/**
* #param args
* #throws IOException
*/
public static void main(String[] args) throws IOException {
ProcessBuilder procBuilder = new ProcessBuilder("cmd.exe");
Process proc = procBuilder.start();
PrintWriter outToProc = new PrintWriter(proc.getOutputStream());
final BufferedReader inFromProc = new BufferedReader(new InputStreamReader(proc.getInputStream()));
final BufferedReader errorFromProc = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
Thread outputThread = new Thread(new Runnable(){
#Override
public void run() {
while(true) {
try {
while(inFromProc.ready()) {
String line = inFromProc.readLine();
System.out.println(line);
}
while(errorFromProc.ready()) {
String line = errorFromProc.readLine();
System.err.println(line);
}
} catch (IOException e) {
throw new RuntimeException("Error in output thread", e);
}
try {
Thread.sleep(100);
} catch(InterruptedException e) {
System.out.println("Output Thread interrupted -> Thread will terminate");
break;
}
}
}
});
outputThread.start();
System.out.println("\n\nProxy shell is ready. Enter 'quit' to leave program.\n\n");
System.out.flush();
String line = null;
while((line = reader.readLine()) != null) {
if(line.equalsIgnoreCase("quit")) {
System.out.println("Good Bye");
break;
}
outToProc.println(line);
outToProc.flush();
}
reader.close();
outputThread.interrupt();
proc.destroy();
}
}

Unable to run Shell Script

Hi i am trying to run shell script from following code
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class ScriptTest {
public static void main(String[] args){
BufferedReader stdErr=null;
BufferedReader stdIn=null;
try{
System.out.println("In Script");
String[] commands= {"ls"};
Process process = Runtime.getRuntime().exec("/mobilityapps/testScript/testScript.sh");
stdIn= new BufferedReader(new InputStreamReader(process.getInputStream()));
stdErr = new BufferedReader(new InputStreamReader(process.getErrorStream()));
String inline= stdIn.readLine();
String errline =stdErr.readLine();
System.out.println("*Inline*"+inline);
System.out.println("*Errline*"+errline);
while(inline!=null){
System.out.println(inline);
inline=stdIn.readLine();
}
while(errline!=null){
System.out.println(errline);
errline=stdErr.readLine();
}
System.out.println("Process Exit Value: "+process.waitFor());
}catch(Exception excp){
excp.printStackTrace();
}
}
}
The script i am trying to call is
CURRDATE=`date '+%d%b%Y'`
TIMESTAMP=`date '+%H:%M'`
BASE_PATH=/mobilityapps/testScript
LOGFILE=${BASE_PATH}/logs_${CURRDATE}_${TIMESTAMP}.log
echo ${CURRDATE} ${TIMESTAMP}>>${LOGFILE}
All both the script and Java program are in the same directory.
When i run testScript.sh from PUTTY it runs fine
But when i run from Java program Process Exit Value is 255
Can anyone suggest the changes?
Try replacing the path
Runtime.getRuntime().exec("/mobilityapps/testScript/testScript.sh");
with
Runtime.getRuntime().exec("./mobilityapps/testScript/testScript.sh");
If you just use / at the begining, it means that it's a absolute path.
Using '.' indicates that is a relative path.

How to run a Perl file using Java? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
How should I call a Perl Script in Java?
I have a perl file which is used for remotely checking ip addresses.I need to run that perl in java.please help me to proceed.
ProcessBuilder example
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import org.apache.commons.io.FileUtils;
OutputStreamWriter writer =null;
BufferedReader stdoutBR = null;
try {
File tmp = new File("temp_dir");
File cmdFile = File.createTempFile("foo", ".sh", tmp);
File stdout = File.createTempFile("foo_stdout", ".txt", tmp);
File stderr = File.createTempFile("foo_stderr", ".txt", tmp);
String script = "/usr/bin/perl foo.pl 2>"+stderr.getAbsolutePath()+" >"+stdout.getAbsolutePath()+" \n";
cmdFile.setExecutable(true);
FileUtils.writeStringToFile(cmdFile, script);
ProcessBuilder processBuilder = new ProcessBuilder(cmdFile.getAbsolutePath());
processBuilder.redirectErrorStream(true);
Process process = processBuilder.start();
InputStream numbStream = process.getInputStream();
stdoutBR = new BufferedReader(new InputStreamReader(numbStream));
String line = null;
StringBuilder unexpectedOutput = new StringBuilder();
while ((line = stdoutBR.readLine()) !=null) {
unexpectedOutput.append(line);
unexpectedOutput.append("\n");
}
process.waitFor();
stdoutBR.close();
log.debug("Process exit value:"+process.exitValue());
if (process.exitValue() != 0) {
String stdoutString = FileUtils.readFileToString(stdout);
String stderrString = FileUtils.readFileToString(stderr);
throw new RuntimeException("Problem executing script. \nOutput:"+unexpectedOutput.toString()+"\nStdout:"+stdoutString+"\nStderr:"+stderrString);
}
String output = FileUtils.readFileToString(stdout);
FileUtils.deleteQuietly(cmdFile);
FileUtils.deleteQuietly(stdout);
FileUtils.deleteQuietly(stderr);
} finally {
try {
if (writer != null) {
writer.close();
}
}
catch (Exception e) {
//TODO
}
}
You need the Runtime.getRuntime().exec() method. Some points to consider:
you must explicitly call perl in the command line: "perl myprog.pl". The implicit interpreter selection that the kernel normally does doesn't work in the exec() method.
you must make sure that the path to perl is in your program's PATH environment,
or in the environment that you pass to the exec() call
you must completely drain the stdout and the stderr of the Process that you created, or the call will not terminate.
(The ProcessBuilder class mentioned above simplifies some of these issues.)

How to invoke a Linux shell command from Java

I am trying to execute some Linux commands from Java using redirection (>&) and pipes (|). How can Java invoke csh or bash commands?
I tried to use this:
Process p = Runtime.getRuntime().exec("shell command");
But it's not compatible with redirections or pipes.
exec does not execute a command in your shell
try
Process p = Runtime.getRuntime().exec(new String[]{"csh","-c","cat /home/narek/pk.txt"});
instead.
EDIT::
I don't have csh on my system so I used bash instead. The following worked for me
Process p = Runtime.getRuntime().exec(new String[]{"bash","-c","ls /home/XXX"});
Use ProcessBuilder to separate commands and arguments instead of spaces. This should work regardless of shell used:
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
public class Test {
public static void main(final String[] args) throws IOException, InterruptedException {
//Build command
List<String> commands = new ArrayList<String>();
commands.add("/bin/cat");
//Add arguments
commands.add("/home/narek/pk.txt");
System.out.println(commands);
//Run macro on target
ProcessBuilder pb = new ProcessBuilder(commands);
pb.directory(new File("/home/narek"));
pb.redirectErrorStream(true);
Process process = pb.start();
//Read output
StringBuilder out = new StringBuilder();
BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = null, previous = null;
while ((line = br.readLine()) != null)
if (!line.equals(previous)) {
previous = line;
out.append(line).append('\n');
System.out.println(line);
}
//Check result
if (process.waitFor() == 0) {
System.out.println("Success!");
System.exit(0);
}
//Abnormal termination: Log command parameters and output and throw ExecutionException
System.err.println(commands);
System.err.println(out.toString());
System.exit(1);
}
}
Building on #Tim's example to make a self-contained method:
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.util.ArrayList;
public class Shell {
/** Returns null if it failed for some reason.
*/
public static ArrayList<String> command(final String cmdline,
final String directory) {
try {
Process process =
new ProcessBuilder(new String[] {"bash", "-c", cmdline})
.redirectErrorStream(true)
.directory(new File(directory))
.start();
ArrayList<String> output = new ArrayList<String>();
BufferedReader br = new BufferedReader(
new InputStreamReader(process.getInputStream()));
String line = null;
while ( (line = br.readLine()) != null )
output.add(line);
//There should really be a timeout here.
if (0 != process.waitFor())
return null;
return output;
} catch (Exception e) {
//Warning: doing this is no good in high quality applications.
//Instead, present appropriate error messages to the user.
//But it's perfectly fine for prototyping.
return null;
}
}
public static void main(String[] args) {
test("which bash");
test("find . -type f -printf '%T#\\\\t%p\\\\n' "
+ "| sort -n | cut -f 2- | "
+ "sed -e 's/ /\\\\\\\\ /g' | xargs ls -halt");
}
static void test(String cmdline) {
ArrayList<String> output = command(cmdline, ".");
if (null == output)
System.out.println("\n\n\t\tCOMMAND FAILED: " + cmdline);
else
for (String line : output)
System.out.println(line);
}
}
(The test example is a command that lists all files in a directory and its subdirectories, recursively, in chronological order.)
By the way, if somebody can tell me why I need four and eight backslashes there, instead of two and four, I can learn something. There is one more level of unescaping happening than what I am counting.
Edit: Just tried this same code on Linux, and there it turns out that I need half as many backslashes in the test command! (That is: the expected number of two and four.) Now it's no longer just weird, it's a portability problem.

Categories