Run multiple system commands - java

I have been playing with java processes for a while and am stuck. What i want to do is run multiple system commands at the same time and print their output to console.
For example, ls -l ; cat someFile ; quit ; grep foo someOtherFile should all be running at the same time. I have read somewhere that the output of these commands should be intermixed. In addition, if there's a quit command anywhere in the string, continue executing other commands and then exit.
Right now, they are executing sequentially. How do I run them concurrently and print their output as it arrive.
String st = "ls -l ; cat someFile ; quit ; grep foo someOtherFile";
String[] rows = st.split(";");
String[][] strArray = new String[rows.length][];
int index = 0;
for(int i = 0; i < rows.length; i++) {
rows[index] = rows[index].trim();
strArray[index] = rows[index].split(" ");
index++;
}
for(int i = 0; i < strArray.length; i++) {
if(rows[i].equalsIgnoreCase("quit")) {
System.out.println("Abort");
break;
}
if(rows[i].equals("")) {
continue;
}
ProcessBuilder pb = new ProcessBuilder(strArray[i]);
pb.redirectErrorStream(true);
Process process = pb.start();
InputStream is = process.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;
while ( (line = br.readLine()) != null) {
System.out.println(line);
}
br.close();
}

Just put the guts of your loop inside the run() function of a new thread, and each iteration of the loop will run in a separate thread:
new Thread() {
public void run() {
// loop guts go here
}
}.start();
You may have to declare a few variables as finals in order to access them inside this anonymous inner class.

You can try code similar to this:
// command list
String st = "ls -la; cat someFile";
String[] commands = st.split(";");
for (int i = 0; i < commands.length; i++) {
String currentCommand = commands[i].trim();
System.out.println("Command: " + currentCommand);
Thread thread = new Thread(() -> {
try {
ProcessBuilder command = new ProcessBuilder(currentCommand);
Process process = command.start();
InputStream is = process.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String line;
while((line = br.readLine()) != null) {
System.out.println(line);
}
br.close();
} catch (IOException e) {
e.printStackTrace();
}
});
thread.start();
}
Disclaimer: not tested on a Linux machine. Windows machines will probably not work. See this link regarding Windows command line process execution.

You should look to some documentation about concurrency, threads an such http://docs.oracle.com/javase/tutorial/essential/concurrency/.
Here an edit to your code that may work, not tested.
String st = "ls -l ; cat someFile ; quit ; grep foo someOtherFile";
String[] rows = st.split(";");
String[][] strArray = new String[rows.length][];
int index = 0;
for(int i = 0; i < rows.length; i++) {
rows[index] = rows[index].trim();
strArray[index] = rows[index].split(" ");
index++;
}
List<Thread> threads = new ArrayList<Thread>();
for(int i = 0; i < strArray.length; i++) {
if(rows[i].equalsIgnoreCase("quit")) {
System.out.println("Abort");
break;
}
if(rows[i].equals("")) {
continue;
}
final int iForThread = i;
Thread thread = new Thread() {
public void run(){
try{
ProcessBuilder pb = new ProcessBuilder(strArray[iForThread]);
pb.redirectErrorStream(true);
Process process = pb.start();
InputStream is = process.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;
while ( (line = br.readLine()) != null) {
System.out.println(line);
}
br.close();
}catch(IOException e){
//Log some awesome error
//Clean up
//Do whatever
}
}
};
threads.add(thread);
}
final CyclicBarrier gate = new CyclicBarrier(threads.size() + 1); //+1 is a tip from other post
for(Thread thread : threads){
thread.start();
}
try {
gate.await();
System.out.println("all threads started");
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
/* RONALDO OF ERROS
* MESSI OF HANDLERS*/
}
}
It creates an tread and executed it at the spot.
I if you are just messing around I think this enough.
Edit: Added start threads at "same time"
Based on: How to start two threads at "exactly" the same time
See:https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CyclicBarrier.html

Related

Java program is not able to execute terminal command

import java.io.*;
import java.io.IOException;
import java.util.Scanner;
public class AutoStart{
public static void main(String[] args){
while(true){
Runtime r = Runtime.getRuntime();
try{
Process p = r.exec("ps -ef >> services.txt");
try{
p.waitFor();
} catch(InterruptedException e){
e.getStackTrace();
}
Scanner txtscan = new Scanner(new File("services.txt"));
int running = 0; //0 means not running and 1 means running
while(txtscan.hasNextLine()){
String str = txtscan.nextLine();
if(str.indexOf("red5") != -1){
running = 1;
}
}
if(running == 0){
//red5 is not running so start it now
//code to start it goes here
}
//at the end remove services.txt file
//code to remove that file goes here.
} catch(IOException e){
e.getStackTrace();
}
try {
Thread.sleep(1000); //1000 milliseconds is one second.
} catch(InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
}
}
On line 10 I am trying to create a text file which contains list of all the running programs but my java program is not able to create it.
This program is not able to create services.txt file and I don't get any error at all so I am confused what's the problem. Can you help me figure out the problem? Thank you.
This calls a subprocess without relying on any shell mechanism, catching the resulting standard output.
public static void main( String[] args ) throws Exception {
try {
ProcessBuilder pb = new ProcessBuilder( "/bin/ps", "-ef" );
Process process = pb.start();
InputStream is = process.getInputStream();
Reader rdr = new InputStreamReader( is );
LineNumberReader lnr = new LineNumberReader(rdr);
String line;
while( (line = lnr.readLine()) != null ){
if( line.contains( "skype" ) ){
System.out.println( "skype is running" );
}
}
process.waitFor();
} catch( Exception e ){
} catch( Error e ){
}
InuThe Process class will not throw an exception if your command returns a non-zero exit code (usually indicating failure). You have to dig into it yourself.
Here is a basic change to your code that will print the error and output stream (command line tools may print to either) to the console upon receiving a non-zero exit code from the process.
Hopefully this helps you figure it out:
import java.io.*;
import java.io.IOException;
import java.util.Scanner;
public class AutoStart{
public static void main(String[] args){
while(true){
Runtime r = Runtime.getRuntime();
try{
Process p = r.exec("ps -ef >> services.txt");
try{
p.waitFor();
} catch(InterruptedException e){
e.getStackTrace();
}
if (p.exitValue() != 0){
BufferedReader br = new BufferedReader(new InputStreamReader(p.getErrorStream()));
System.out.println("Error Stream:");
String line;
while ((line = br.readLine()) != null){
System.out.println(line);
}
br = new BufferedReader(new InputStreamReader(p.getInputStream()));
System.out.println("Output Stream:");
while ((line = br.readLine()) != null){
System.out.println(line);
}
System.exit(1);
}
Scanner txtscan = new Scanner(new File("services.txt"));
int running = 0; //0 means not running and 1 means running
while(txtscan.hasNextLine()){
String str = txtscan.nextLine();
if(str.indexOf("red5") != -1){
running = 1;
}
}
if(running == 0){
//red5 is not running so start it now
//code to start it goes here
}
//at the end remove services.txt file
//code to remove that file goes here.
} catch(IOException e){
e.getStackTrace();
}
try {
Thread.sleep(1000); //1000 milliseconds is one second.
} catch(InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
}
}

ProcessBuilder.start() with "su" command blocks thread

I'm implementing a terminal "emulator"/"launcher" in my app. I want to let the user to use all android shell commands. This works great, until I use the "su" command. here is the source code:
Code:
ProcessBuilder processBuilder = new ProcessBuilder(input);
processBuilder.directory(info.currentDirectory);
Process process;
try {
process = processBuilder.start();
} catch (IOException e) {
return 1;
}
process.waitFor();
InputStream i = process.getInputStream();
InputStream e = process.getErrorStream();
BufferedReader ir = new BufferedReader(new InputStreamReader(i));
BufferedReader er = new BufferedReader(new InputStreamReader(e));
String s = null;
output = "";
for(int count = 0; count == 0 || s != null; count++) {
s = ir.readLine();
if(s != null) {
if(count == 0)
output = output.concat(mContext.getString(R.string.output_label) + "\n");
output = output.concat(s + "\n");
}
}
s = null;
for(int count = 0; count == 0 || s != null; count++) {
s = er.readLine();
if(s != null) {
if(count == 0)
output = output.concat(mContext.getString(R.string.error_label) + "\n");
output = output.concat(s + "\n");
}
}
process.destroy();
Main thread is blocked forever in any case: if I call only process.waitFor, and if I use one of the InputStream objects.
What's the problem? SU permissions are granted normally...

Java ProcessBuilder to start multiple java processes

Can I spawn multiple different JVMs given the same Main.class, arguments and VM options?
Is it possible to do it with the ProcessBuilder?
Here is a basic example using Process that starts 10 different JVM process:
for (int i = 0; i < 10; i++) {
new Thread(new Runnable() {
public void run() {
try {
//start a new jvm with 256m of memory with the MyClass passing 2 parameters
String cmd = "java -Xmx256M -cp myjar.jar com.mymainclass.MyClass par1 par2";
Process p = Runtime.getRuntime().exec(cmd);
BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = br.readLine();
while (line != null) {
line = br.readLine();
}
br = new BufferedReader(new InputStreamReader(p.getErrorStream()));
line = br.readLine();
while (line != null) {
line = br.readLine();
}
} catch (IOException e) {
}
}
}).start();
}

Fetch and store output from a subprocess in Java

I'm working on something that requires me to start to subprocess(command prompt) and execute some commands on it. I need to fetch the output from the subprocess and store it in a file or String.
here's what I have done so far, and it doesn't work:
public static void main(String args[])
{
try
{
Runtime RT = Runtime.getRuntime();
String command = "cmd /c start javap java.lang.String";
File file = new File("write.txt");
Writer output = new BufferedWriter(new FileWriter(file));
BufferedReader br = new(BufferedReader(newInputStreamReader(RT.exec(command).getInputStream()));
String temp = br.readLine();
while(!temp.equals(null))
{
output.write(temp);
temp = br.readLine();
}
output.close();
RT.exec("exit");
}
catch(Exception e)
{
System.out.println(e);
}
}
Start changing this:
new(BufferedReader(newInputStreamReader(
To:
new BufferedReader(new InputStreamReader(
Compile and see if you still have the problem
edit
Also, there is a good reason why you shouldn't catch Exception, you also catch programming errors like a NullPointerException
while( !temp.equals(null)) { //Throws NullPointerExceptin when temp is null
Change it with:
while( temp != null ) { //!temp.equals(null)) {
Finally you don't have to "exit" since you're not inside the cmd really.
Corrected version
This version runs as you intend:
import java.io.*;
class Rt {
public static void main(String args[]) throws Exception {
Runtime RT = Runtime.getRuntime();
String command = "javap java.lang.String" ;
File file = new File("write.txt");
Writer output = new BufferedWriter(new FileWriter(file));
BufferedReader br = new BufferedReader(new InputStreamReader(RT.exec(command).getInputStream()));
String temp = br.readLine();
while( temp != null ) { //!temp.equals(null)) {
output.write(temp);
temp = br.readLine();
}
output.close();
//RT.exec("exit");
}
}
edit
Final remarks:
Since Java 1.5 the preferred way to invoke a command is using ProcessBuilder and it is better if you use an array of strings instead of a single string ( or varargs ).
When you're building your output you can get rid of the file object and pass the file name directly to the filewriter.
While reading the line you can assign and evaluate in the condition.
Java's coding conventions suggest to use the opening brace in the same like.
This would be my version of your code:
class Rt {
public static void main(String args[]) throws Exception {
Writer output = new BufferedWriter(new FileWriter ( "write.txt"));
InputStream in = new ProcessBuilder("javap", "java.lang.String").start().getInputStream();
BufferedReader br = new BufferedReader( new InputStreamReader(in));
String line = null;
while( ( line = br.readLine() ) != null ) {
output.write( line );
}
output.close();
}
}
It might need still some work, but I hope it helps you.
Here is an example which should work:
StringBuffer outStream = new StringBuffer();
StringBuffer errStream = new StringBuffer();
Runtime runtime = Runtime.getRuntime();
Process process = null;
try {
process = runtime.exec(command);
} catch (IOException ex) {
ex.printStackTrace();
return;
}
InputStream outIs = process.getInputStream();
MonitorOutputThread sout = new MonitorOutputThread(outIs, outStream);
sout.run();
InputStream errIs = process.getErrorStream();
MonitorOutputThread serr = new MonitorOutputThread(errIs, errStream);
serr.run();
while (sout.isAlive() || serr.isAlive()) {
try {
sleep(100);
} catch (InterruptedException ex) {
ex.printStackTrace();
// ignore
}
}
And the code for MonitorOutputThread
private class MonitorOutputThread extends Thread {
private final InputStream is;
private final StringBuffer output;
public MonitorOutputThread(InputStream is, StringBuffer output) {
this.is = is;
this.output = output;
}
#Override
public void run() {
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line = null;
try {
while ((line = br.readLine()) != null) {
output.append(line);
output.append(LINE_SEPARATOR);
}
if (output.length() >= 1) {
char lastChar = output.charAt(output.length() - 1);
if (lastChar == '\n') {
output.deleteCharAt(output.length() - 1);
}
}
} catch (IOException ex) {
ex.printStackTrace();
return;
}
}
}
This should catch both the standard output and standard error of the command.
DevDaily has a simple example of how to work with Process class.
See the snippet:
import java.io.*;
public class JavaRunCommand {
public static void main(String args[]) {
String s = null;
try {
// run the Unix "ps -ef" command
// using the Runtime exec method:
Process p = Runtime.getRuntime().exec("ps -ef");
BufferedReader stdInput = new BufferedReader(new
InputStreamReader(p.getInputStream()));
BufferedReader stdError = new BufferedReader(new
InputStreamReader(p.getErrorStream()));
// read the output from the command
System.out.println("Here is the standard output of the command:\n");
while ((s = stdInput.readLine()) != null) {
System.out.println(s);
}
// read any errors from the attempted command
System.out.println("Here is the standard error of the command (if any):\n");
while ((s = stdError.readLine()) != null) {
System.out.println(s);
}
System.exit(0);
}
catch (IOException e) {
System.out.println("exception happened - here's what I know: ");
e.printStackTrace();
System.exit(-1);
}
}
}
or even check this code I've writen some time ago

Runtime.getRuntime().exec(cmd); appending previous output with each new execution?

I am running into this problem.
my program invokes Runtime.getRuntime().exec(cmd); on a windows platform. I read the error and output stream and do something with this output. This method gets called in a loop after each 4-5 seconds and it goes on till the program is terminated.
Now what happens, each time i read the output, the previous output is appended to the new output and as such with each iteration the result grows bigger and bigger. Is there anyway to stop this thing. The command executed is "tasklist" with some filtering parameters.
I have made a method (which returns String output) for this Runtime.getTuntime().exec(cmd) in which i am also closing the process after execution but when it is called from within the loop, each time previous output is appended to the new one.
Here is the code:
class Track implements Runnable {
static int size = 0;
public void run() {
String cmd1 = "tasklist /fo list /fi \"imagename eq java.exe\"";
String cmd2 = "tasklist /fo list /fi \"imagename eq javaw.exe\"";
String text = "";
int i=1, j=0;
while(size < 100000){
try{
text = fList.pList(cmd2, 1);
if (text.indexOf("javaw.exe")== -1){
text = fList.pList(cmd1, 1);
}
if(j==22) System.out.println(text);
if (text.charAt(0)!= '0') continue;
i = text.lastIndexOf("Mem Usage: ")+14;
text = text.substring(i);
text = text.substring(0,text.lastIndexOf(" K"));
text = text.replaceFirst(",", "");
size = Integer.parseInt(text);
System.out.println(size);
Thread.sleep(3000);
j++;
} catch(Exception e){
System.out.println(e);
}
}
System.out.println("Memory utlization exceeded the permissible limit");
System.out.println("Now terminating the Program\n");
System.exit(1);
}
static void memoryCheck(int size) throws Exception{
(new Thread(new Track())).start();
}
}
in class fList is the method pList:
static String pList(String cmd, int eval) throws Exception{ //can execute external command
String out = "";
int val = 5; // should not be zero, to verify returned code zero for normal exec.
try
{
//String osName = System.getProperty("os.name" );
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec(cmd);
// any error message?
eProcList error = new eProcList(proc.getErrorStream());
// any output?
eProcList output = new eProcList(proc.getInputStream());
// kick them off
error.start();
output.start();
// any error???
int exitVal = proc.waitFor();
out = eProcList.procList();
val = exitVal;
proc.destroy();
proc.getInputStream().close();
proc.getErrorStream().close();
} catch (Throwable t)
{
t.printStackTrace();
}
if (eval==1) return val + out;
return out;
}
class eProcList extends Thread
{
InputStream iStream;
static String oPut = "";
eProcList(InputStream iStream)
{
this.iStream = iStream;
}
public void run()
{
try
{
InputStreamReader isr = new InputStreamReader(iStream);
BufferedReader br = new BufferedReader(isr);
String line=null;
while ( (line = br.readLine()) != null)
oPut = oPut + line+"\n";
} catch (IOException e)
{
e.printStackTrace();
}
}
static public String procList(){
return oPut;
}
}
you asked so iv'e copied all here.
You made oPut a static field - its initialized to "" once when the class is loaded and then shared between every new instance of eProcList, i.e. never cleared of the previous run. Either don't make it static (why is it static?) or clear it in the constructor.

Categories

Resources