I'm working on a project and I would like to execute programs in the windows console or a linux terminal.
Instead of launching a new console and working the program in it I want to do something like the following:
rt.exec("cmd.exe /c start cmd.exe /k ruby rubycode.rb");
From this point on I want the user to be able to work with the program from the GUI/my program. The idea in my min is starting cmd in silent mode where it is not visible and latching on to it. Then redirecting the console output to the GUI and letting the user input data to the console through the GUI.
A similar concept is what most IDEs like jgrasp do. When you run a program you interface with it though their own command prompt.
How is this done? Iv'e tried grabbing the IOStreams from the process and trying to atleast print what the console outputs but no luck.
Here is an example:
public class ProcessTest {
private Process p;
private BufferedReader reader;
private BufferedWriter writer;
public void start() throws IOException {
ProcessBuilder pb = new ProcessBuilder("cmd", "/c", "dir");
pb.directory(new File("./"));
this.p = pb.start();
this.reader = new BufferedReader(new InputStreamReader(this.p.getInputStream()));
this.writer = new BufferedWriter(new OutputStreamWriter(this.p.getOutputStream()));
new Read(this.reader).start();
}
public boolean writeToConsole(String s) throws IOException {
if (p == null)
return false;
this.writer.write(s + "\n");
this.writer.flush();
return true;
}
public class Read extends Thread {
private BufferedReader reader;
public Read(BufferedReader reader) {
this.reader = reader;
}
public void run() {
try {
String line;
while ((line = this.reader.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
try {
new ProcessTest().start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
With the writeToConsole method you can write any string to the programm that you executed.
Related
I am trying to read real-time the data from a process using a BufferedReader and redirect it to a TextArea. However, I have noticed that when the process is running the .bat, it tends to freeze and cause a lag to the JavaFX TextArea. The ".bat" fiel that runs prints out a ..... one one line to indicate progress, and I believe this is where it is failing at.
I had an idea to have the program wait a certain amount of time, then it executes, but because its all on one line it also fails. Please help
Code:
while(iterator.hasNext()) {
Map.Entry mentry = (Map.Entry)iterator.next();
String taskPath = " /k d: && cd DATA\\Virtualization\\Users && ESXRun.bat";
ProcessBuilder pb = new ProcessBuilder("cmd",taskPath);
Process process = pb.start();
BufferedReader stdInput = new BufferedReader(new InputStreamReader(process.getInputStream()));
String s = "";
// read the output from the command
while ((s = stdInput.readLine()) != null) {
//TextArea
cliLog.appendText(s);
cliLog.appendText("\n");
}
process.waitFor();
process.destroy();
}
This is just the concept to demonstrate the issue.
You have to customize it and handle exceptions.
public class TextAreaBash extends Application implements Runnable {
private final TextArea textArea = new TextArea();
public static void main(final String[] args) {
Application.launch(args);
}
#Override
public void start(final Stage primaryStage) throws Exception {
primaryStage.setScene(new Scene(new VBox(textArea), 300, 200));
primaryStage.show();
ping();
}
public void ping() {
new Thread(this).start();
}
#Override
public void run() {
try {
final ProcessBuilder processBuilder = new ProcessBuilder("cmd", "/C", "ping -a www.google.com -n 10");
final Process process = processBuilder.start();
final InputStreamReader inputStreamReader = new InputStreamReader(process.getInputStream());
while (appendText(inputStreamReader)) {
;
}
process.waitFor();
process.destroy();
} catch (final Exception ex) {
ex.printStackTrace();
}
}
private boolean appendText(final InputStreamReader inputStreamReader) {
try {
final char[] buf = new char[256];
final int read = inputStreamReader.read(buf);
if (read < 1) {
return false;
}
Platform.runLater(() -> {
textArea.appendText(new String(buf));
});
return true;
} catch (final IOException e) {
e.printStackTrace();
}
return false;
}
}
This is my main class, wherein run(), I am calling one another method install setup() which is for exe files.
public static void main(String[] args) {
launch(args);
}
public void startSetup() {
Runnable task=new Runnable() {
#Override
public void run() {
try {
Thread.sleep(1000);
installSetup();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
Thread thread=new Thread(task);
thread.start();
}
Here is my installsetup() method
public void installSetup() {
try {
Runtime.getRuntime().exec("cmd /c C:path\\setup.exe", null, new File("C:pathfolder\\01_Setupexe"));
//process.waitFor();
} catch (IOException e) {
e.printStackTrace();
}
};
I am calling it in my controller class like this:
public class Controller extends Thread {
#FXML
private ComboBox<?> dsetup;
public void generateRandom() {
if(dsetup.getValue()!=null) dsetupValue = dsetup.getValue().toString();
if(dsetupValue!=null)call.startSetup();
Before I was just calling the install files with the exec method but not with threads concept, the application was working fine, but it was executing all the.exe files at once and then my interface freezes. So now I am using threads concept and trying to implement one thread at a time. I don't understand if it is a wrong way or not, but I do not get any error in console.
Runtime.exec has been obsolete for many years. Use ProcessBuilder instead:
ProcessBuilder builder = new ProcessBuilder("C:\\path\\setup.exe");
builder.directory(new File("C:pathfolder\\01_Setupexe"));
builder.inheritIO();
builder.start();
The inheritIO() method will make the spawned process use the Java program’s stdin, stdout, and stderr, so it will not hang waiting for input or waiting for an available output buffer.
I doubt you need the new Thread or the sleep call, but I don’t know what files you’re calling or whether they depend on each other.
Sadly exec has some pitfalls. Most of the time using the process aproche (see Listing 4.3) saved me related to buffer issues and so on.
https://www.javaworld.com/article/2071275/core-java/when-runtime-exec---won-t.html
import java.util.*;
import java.io.*;
public class MediocreExecJavac
{
public static void main(String args[])
{
try
{
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec("javac");
InputStream stderr = proc.getErrorStream();
InputStreamReader isr = new InputStreamReader(stderr);
BufferedReader br = new BufferedReader(isr);
String line = null;
System.out.println("<ERROR>");
while ( (line = br.readLine()) != null)
System.out.println(line);
System.out.println("</ERROR>");
int exitVal = proc.waitFor();
System.out.println("Process exitValue: " + exitVal);
} catch (Throwable t)
{
t.printStackTrace();
}
}
}
Source: javaworld
Real Goal: create a program that calls other programs(lab exercises)
Current goal: Make Main.java run Lab4 a GUI program (Lab4Ans201506159.java - the filename)
Lab4Form and Lab4Intro are forms
here is the Main.java code
public class Main {
public static void main(String[] args) throws IOException {
// TODO code application logic here
Process p,p2,p3,p4;
p = Runtime.getRuntime().exec("javac Lab4Ans201506159.java");
//p3 = Runtime.getRuntime().exec("javac Lab4Ans201506159Form.java");
//p4 = Runtime.getRuntime().exec("javac Lab4Ans201506159Intro.java");
p2 = Runtime.getRuntime().exec("java Lab4Ans201506159");
//p2 = Runtime.getRuntime().exec("Lab4Ans201506159");
}
and here is the Lab4 code
Lab4Form and Lab4Intro are Frames
what Lab4 is trying to do displaying Lab4Intro, and when it is closed, Lab4Form would be visible
public class Lab4Ans201506159 {
public static void main(String[] args) throws InterruptedException {
Lab4Ans201506159Intro intro = new Lab4Ans201506159Intro();
intro.setLocationRelativeTo(null);
intro.setVisible(true);
Thread.sleep(2000);
//Lab4Ans201506159Form form = new Lab4Ans201506159Form();
while(intro.isActive())
{
}
if(intro.isActive() == false){
Lab4Ans201506159Form form = new Lab4Ans201506159Form();
form.setLocationRelativeTo(null);
form.setVisible(true);
}
}
Problem: Running Main.java will result to a "BUILD SUCCESSFUL" in the compiler but no GUI is displayed. I need answers why it does not display or work.
I suspect only the first Process is executed, in order to be sure, have you already tried to redirect the output of Runtime.exec to the standard output
something like that:
public static void main(String[] args) throws Exception {
System.setOut(new PrintStream(new FileOutputStream("log.txt")));
System.out.println("Init...");
try {
String line;
Process p = Runtime.getRuntime().exec( "javac Lab4Ans201506159.java" );
BufferedReader in = new BufferedReader(
new InputStreamReader(p.getInputStream()) );
while ((line = in.readLine()) != null) {
System.out.println(line);
}
in.close();
}
Thread.sleep(1000);
Process p2 = Runtime.getRuntime().exec("java Lab4Ans201506159" );
BufferedReader in2 = new BufferedReader(
new InputStreamReader(p2.getInputStream()) );
while ((line = in2.readLine()) != null) {
System.out.println(line);
}
in2.close();
}
catch (Throwable e) {
e.printStacktrace();
}
}
like that you can verify what is going wrong...
good luck
I managed to finish my end goal which is to open Lab4. I sort of took a different method though. I suspect one of the reasons why it does not work is because my classpath must have been wrong. I could say that because I can't compile (javac) in CMD Prompt. So I fixed that, then I 'clean and build' (using Netbeans) the project(lab4,intro,form). After that, in the last line of the compiler there will be a line like "java -jar C:\sdfsafs\blablabal". That was the line I used inside runtime.exec() and it finally worked.
public static void main(String[] args) throws Exception {
try {
runProcess("java -jar \"C:\\Users\\Aldrin\\Desktop\\201506159AnsLab4\\dist\\201506159AnsLab4.jar\"");
//runProcess("dir");
//runProcess("java Lab4Ans201506159");
} catch (Exception e) {
e.printStackTrace();
}
}
I still have not answered why the original code does not work though.
I would like my Java program to execute a bash script and return the output back to Java. The trick is my script starts some sort of 'interactive session' and I suppose that is why my Java application freezes (Enters an infinite loop I suppose). Here is the code I use to execute the script, I use ProcessBuilder in order to do that. I also tried
Runtime.getRuntime().exec(PathToScript);
It doesn't work either.
public class test1 {
public static void main(String a[]) throws InterruptedException, IOException {
List<String> commands = new ArrayList<String>();
List<String> commands1 = new ArrayList<String>();
commands.add("/Path/To/Script/skrypt3.sh");
commands.add("> /dev/ttys002");
ProcessBuilder pb = new ProcessBuilder(commands);
pb.redirectErrorStream(true);
try {
Process prs = pb.start();
Thread inThread = new Thread(new In(prs.getInputStream()));
inThread.start();
Thread.sleep(1000);
OutputStream writeTo = prs.getOutputStream();
writeTo.write("oops\n".getBytes());
writeTo.flush();
writeTo.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
class In implements Runnable {
private InputStream is;
public In(InputStream is) {
this.is = is;
}
#Override
public void run() {
try {
byte[] b = new byte[1024];
int size = 0;
while ((size = is.read(b)) != -1) {
System.out.println(new String(b));
}
is.close();
} catch (IOException ex) {
Logger.getLogger(In.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
And here is the script I try to execute. It works like a charm when I run it directly from terminal.
#!/bin/bash
drozer console connect << EOF > /dev/ttys002
permissions
run app.package.info -a com.mwr.example.sieve
exit
EOF
You should not be trying to add redirect instructions as part of the command name:
commands.add("/Path/To/Script/skrypt3.sh");
commands.add("> /dev/ttys002");
ProcessBuilder pb = new ProcessBuilder(commands);
Instead, use the redirectOutput method, something like this:
tty = new File("/dev/ttys002");
ProcessBuilder pb = new ProcessBuilder("/Path/To/Script/skrypt3.sh")
.redirectOutput(ProcessBuilder.Redirect.appendTo(tty))
.redirectError(ProcessBuilder.Redirect.appendTo(tty))
.start();
Though, it appears your bash script is already handling the redirection so not sure you need to do that in Java.
See this answer for more info.
I am writing a program that utilizes a third party mathematics software, "Maxima". This program is a command line interface, and so it can communicate through my Java program with simple I/O routing. I have already figured out how to run the program from within Java, and I have read a lot about how I can reconfigure System.out and how InputStreams/OutputStreams work, but I can't figure out how to do the following (what I think should be a pretty simple task):
Output to Maxima a command from Java, (like the string "5 + 5;")
Retrieve Maxima's output, and deal with it from Java code (like maybe printing the given string + "blah").
Output another command to Maxima from Java...
etc.
-
Below is code which will run Maxima and allow me to interact with it on the Eclipse Console
public static void main(final String[] args) {
// An idea I had for manipulaing how the printstream works.
// Set the system.out to be a custom Prinstream.
// final PrintStream interceptor = new Interceptor(origOut);
// System.setOut(interceptor);
// Run the program:
final String programLocation = "\"C:\\Program Files (x86)\\Maxima-sbcl-5.37.2\\bin\\maxima.bat\"";
final ProcessBuilder pb = new ProcessBuilder();
pb.redirectInput(Redirect.INHERIT); // Inherit I/O
pb.redirectOutput(Redirect.INHERIT);
pb.command(programLocation);
try {
// Start the program and allow it to run in Eclipse's/the program's
// console.
pb.start().waitFor();
} catch (final InterruptedException e) {
e.printStackTrace();
} catch (final IOException e) {
e.printStackTrace();
}
}
This allows for the following style of interaction:
Thanks to the words of wisdom from #RealSkeptic, I think I worked out a solution here.
The key was building a BufferedWriter, and a BufferedReader to interact with the I/O of Maxima. That is:
BufferedWriter w = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
BufferedReader r = new BufferedReader(new InputStreamReader(process.getInputStream()));
Those two lines of code create buffered readers and writers which can input data to Maxima, and read what Maxima output. Here is a (fairly lengthy) use case of this method, which I use to do basically what I asked in the question:
public class TestClass {
public static void main(final String[] args) {
#SuppressWarnings("unused")
final TestClass ts = new TestClass();
}
private BufferedWriter w;
private BufferedReader r;
public TestClass() {
// Start the process using process builder
final String programLocation = "\"C:\\Program Files (x86)\\Maxima-sbcl-5.37.2\\bin\\maxima.bat\"";
final ProcessBuilder pb = new ProcessBuilder();
pb.command(programLocation);
Process process;
try {
process = pb.start();
} catch (final IOException e) {
e.printStackTrace();
process = null;
// killProgram();
}
// Build your own wrappers for communicating with the program.
w = new BufferedWriter(
new OutputStreamWriter(process.getOutputStream()));
r = new BufferedReader(new InputStreamReader(process.getInputStream()));
// Print the five starting messages.
printFromBuffer();
printFromBuffer();
printFromBuffer();
printFromBuffer();
printFromBuffer();
// Run the following three commands in Maxima
runCommand("5+5;");
runCommand("2*65;");
runCommand("quit();");
}
/**
* Runs the given string and prints out the returned answer.
*/
private void runCommand(final String s) {
try {
w.write(s);
w.flush();
printFromBuffer();
printFromBuffer();
} catch (final IOException e) {
e.printStackTrace();
}
}
private void printFromBuffer() {
try {
final String s = r.readLine();
System.out.println(s + " -blah");
} catch (final IOException e) {
System.err.println(e.getMessage());
e.printStackTrace();
}
}
}