Reputation: 17
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();
}
Upvotes: 2
Views: 245
Reputation: 628
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
Upvotes: 0
Reputation: 47213
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.
Upvotes: 0
Reputation: 124
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.
Upvotes: 1