How to run another java process with console in java (in Linux) - java

How can I run an another java process (with a console) in Linux?
I know I should use ProcessBuilder or Runtime.getRuntime().exec() to execute a command,
but I want to know how I can show an separate X-window command terminal (ex. /usr/bin/xterm) or at least show an console-terminal looking window and run a java process with stdin,stdout,stderr on that.
Is there any solution? I heard the Process.getOutputStream() doesn't work on xterm, but haven't tried it yet (Because I'm using Windows..)
EDIT: The java program I want to execute uses jline, which uses JNI...

To start terminl you can simply run following code:
new ProcessBuilder("/usr/bin/xterm").start();
But I guess, that is not you really need. Because, even you pass command to run, let's say ls as argument:
new ProcessBuilder("/usr/bin/xterm", "-e", "ls").start();
You will get output from xterm(not from ls). If you want to start process and get output, you need to do it like that:
public static void main(String[] args) throws Exception {
// get content of the "/usr/bin" directory
ProcessBuilder pb = new ProcessBuilder("ls", "/usr/bin");
pb.redirectErrorStream(true);
Process p = pb.start();
InputStream is = p.getInputStream();
System.out.println(toString(is));
is.close();
}
public static String toString(InputStream is) throws IOException {
Writer writer = new StringWriter();
char[] buffer = new char[1024];
Reader reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
int n;
while ((n = reader.read(buffer)) != -1) {
writer.write(buffer, 0, n);
}
return writer.toString();
}

Related

Issue in calling Python code from Java (without using jython)

I found this as one of the ways to run (using exec() method) python script from java. I have one simple print statement in python file. However, my program is doing nothing when I run it. It neither prints the statement written in python file nor throws an exception. The program just terminates doing nothing:
Process p = Runtime.getRuntime().exec("C:\\Python\\Python36-32\\python.exe C:\\test2.py");
Even this is not creating the output file:
Process p = Runtime.getRuntime().exec("C:\\Python\\Python36-32\\python.exe C:\\test2.py output.txt 2>&1");
What is the issue?
I think you could try your luck with the ProcessBuilder class.
If I read the Oracle documentation correctly, the std inputs and outputs are directed to pipes by default but the ProcessBuilder has an easy method for you to explicitly set output (or input) to a file on your system or something else.
If you want your Python program to use the same output as your Java program (likely stdout and stderr), you can use stg like this:
ProcessBuilder pb = new ProcessBuilder("C:\\Python\\Python36-32\\python.exe", "C:\\test2.py");
pb.redirectOutput(Redirect.INHERIT);
Process p = pb.start();
You can use the ProcessBuilder API, redirecting the output to a file and then wait for the result.
public class Main {
public static final String PYTHON_PATH = "D:\\Anaconda3\\python.exe";
public static final String PATH_TO_SCRIPT = "D:\\projects\\StartScript\\test.py";
public static void main(String[] args) throws IOException, InterruptedException {
ProcessBuilder builder = new ProcessBuilder();
builder.command(PYTHON_PATH, PATH_TO_SCRIPT);
// Redirect output to a file
builder.redirectOutput(new File("output.txt"));
builder.start().waitFor();
// Print output to console
ProcessBuilder.Redirect output = builder.redirectOutput();
File outputFile = output.file();
BufferedReader br = new BufferedReader(new FileReader(outputFile));
String st;
while ((st = br.readLine()) != null) {
System.out.println(st);
}
}
}
The python file test.py contains a simple print statement:
print("Hello from python")
I guess it would be even simpler, if you do not need to wait for the result.
Using the Process API should work, too.
Like in your example (I am using the same constants declared above):
Process p = Runtime.getRuntime().exec(PYTHON_PATH + " " + PATH_TO_SCRIPT);
p.waitFor();
byte[] buffer = new byte[1024];
byte[] errBuffer = new byte[1024];
p.getInputStream().read(buffer);
p.getErrorStream().read(errBuffer);
System.out.println(new String(buffer));
System.out.println(new String(errBuffer));
To see the output of the print statement, you need to wait and redirect the streams. Same for the error stream.
Now if you break the python script like this:
print("Hello from python')
you should be able to see the error printed as well.
One way to start a python process is using an entrypoint - test.cmd
echo Hello
python hello.py
here is hello.py
#!/usr/bin/env python3
import os
if not os.path.exists('dir'):
os.makedirs('dir')
Here is my Java code:
public static void main(String[] args) throws IOException {
try {
Process p = Runtime.getRuntime().exec("test.cmd");
p.waitFor();
Scanner sc = new Scanner(p.getInputStream());
while(sc.hasNextLine()){
System.out.println(sc.nextLine());
}
sc.close();
} catch (Exception err) {
err.printStackTrace();
}
}

Creating named pipes in Java

I am experimenting with creating named pipes using Java. I am using Linux. However, I am running into a problem where writing to the pipe hangs.
File fifo = fifoCreator.createFifoPipe("fifo");
String[] command = new String[] {"cat", fifo.getAbsolutePath()};
process = Runtime.getRuntime().exec(command);
FileWriter fw = new FileWriter(fifo.getAbsoluteFile());
BufferedWriter bw = new BufferedWriter(fw);
bw.write(boxString); //hangs here
bw.close();
process.waitFor();
fifoCreator.removeFifoPipe(fifo.toString());
fifoCreator:
#Override
public File createFifoPipe(String fifoName) throws IOException, InterruptedException {
Path fifoPath = propertiesManager.getTmpFilePath(fifoName);
Process process = null;
String[] command = new String[] {"mkfifo", fifoPath.toString()};
process = Runtime.getRuntime().exec(command);
process.waitFor();
return new File(fifoPath.toString());
}
#Override
public File getFifoPipe(String fifoName) {
Path fifoPath = propertiesManager.getTmpFilePath(fifoName);
return new File(fifoPath.toString());
}
#Override
public void removeFifoPipe(String fifoName) throws IOException {
Files.delete(propertiesManager.getTmpFilePath(fifoName));
}
I am writing a string that consists of 1000 lines. Writing 100 lines work but 1000 lines doesn't.
However, if I run "cat fifo" on an external shell, then the program proceeds and writes everything out without hanging. Its strange how the cat subprocess launched by this program doesn't work.
EDIT: I did a ps on the subprocess and it has the status "S".
External processes have input and output that you need to handle. Otherwise, they may hang, though the exact point at which they hang varies.
The easiest way to solve your issue is to change every occurrence of this:
process = Runtime.getRuntime().exec(command);
to this:
process = new ProcessBuilder(command).inheritIO().start();
Runtime.exec is obsolete. Use ProcessBuilder instead.
UPDATE:
inheritIO() is shorthand for redirecting all of the Process's input and output to those of the parent Java process. You can instead redirect only the input, and read the output yourself:
process = new ProcessBuilder(command).redirectInput(
ProcessBuilder.Redirect.INHERIT).start();
Then you will need to read the process's output from process.getInputStream().

Java runtime.exec does not execute correctly

I am getting an exe-File, which I have to execute using Java (Version 6) on Windows Server 2008 R2. Now there is s problem I do not really understand. When executing the file with the commandline
"C:\test.exe param1 param2"
it works correctly, but when I execute the file with
Process proc = Runtime.getRuntime().exec("C:\\test.exe param1 param2");
proc.waitFor();
I can see the test.exe in the windows task manager and it starts running (it creates a log which states that), but then it simply doesn't do anything anymore. The test.exe endlessly runs with 0% and I have to kill the process manually. After doing so the java-program continues and
proc.exitValue()
is "1", therefore java recognizes that I have killed the process. I also tried writing the commandline in a batchfile and executing it with .exec() but it didn't change anything.
What really confuses me, is that it runs perfectly via windows command-line, but does not via .exec(). Does anyone have an idea what might cause such a problem? Or is it more likely that the test.exe is causing the problem?
In best regards
Edit: Wrote down the wrong path in .exec
Since your program procudes a lot of output, my hypothesis is that it is stuck trying to write to the standard output (which is a pipe under Linux, don't know for Windows).
Try this:
final byte[] devnull = new byte[1024];
final ProcessBuilder builder = new ProcessBuilder("C:\\test.exe", "param1", "param2")
.redirectErrorStream(true);
final Process p = builder.start();
final InputStream stdout = process.getInputStream();
// Purge stdout
while (stdout.read[devnull] != -1);
// Grab the process' exit code here
As fge pointed out in https://stackoverflow.com/a/21903969 , it is important to consume all the output that is produced by the process - not only on Linux, but also on Windows, and not only the standard output, but also the possible errors.
The general pattern for this could look like this:
private static void runCommand(String command) throws IOException
{
Process process = Runtime.getRuntime().exec(command);
String errorMessage =
new String(toByteArray(process.getErrorStream()));
String outputMessage =
new String(toByteArray(process.getInputStream()));
int exitValue = 0;
try
{
exitValue = process.waitFor();
}
catch (InterruptedException e)
{
Thread.currentThread().interrupt();
}
System.out.println("Output message: "+outputMessage);
System.out.println("Error message: "+errorMessage);
System.out.println("Exit value: "+exitValue);
}
private static byte[] toByteArray(
InputStream inputStream) throws IOException
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte buffer[] = new byte[8192];
while (true)
{
int read = inputStream.read(buffer);
if (read == -1)
{
break;
}
baos.write(buffer, 0, read);
}
return baos.toByteArray();
}
"C:\test.exe param1 param2"
You have a tab in there. Try this:
"C:\\test.exe param1 param2"
If the process produces any output on either stdout or stderr you need to consume it. Otherwise it can block.

runtime.exec() taking infinite time to execute code

I want to execute a command which takes 2 arguments.
1.input file name
2.output file name.
The command is sixV1.1 outputFile.txt
The code is:
String cmd= "sixV1.1 <inputFile.txt >outputFile.txt";
Process p=Runtime.getRuntime().exec(cmd);
int retValue=p.waitFor();
when the i run above code,it is taking infinite time.
Is it possible to give <, > charecters in cmd .Please suggest me....
The right way to do input/output redirection when you start a process in Java is to write/read from the process's streams:
Process p = Runtime.getRuntime().exec("sixV1.1");
InputStream is = p.getInputStream();
// read from is and write to outputFile.txt
OutputStream os = p.getOutputStream();
// read from inputFile.txt and write to os
There's a fantastic blog post by Michael C. Daconta about successful command line calls using Runtime in Java. It's not as easy as you might think!
The following code extract from that blog post describes "MediocreExecJava", a class that successfully runs a program using Runtime.exec() and manages its input and output without hanging. I've used it before and it works. I highly recommend reading the post to understand why!
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();
}
}
}

Processbuilder without redirecting StdOut

Is it possible to redirect the output stream back into a process, or not redirect it at all?
The backstory:
I am trying to launch an executable using processbuilder.
(Source dedicated server / srcds.exe to be exact)
As a result of launching it with the processbuilder, the console window of this executable remains empty. A few seconds after launch, the executable crashes with the error "CTextConsoleWin32::GetLine: !GetNumberOfConsoleInputEvents" because its console is empty.
I think you're talking about making the launched process' stdout go to the current process' stdout. If you're using JDK7, that's as simple as:
.redirectOutput(ProcessBuilder.Redirect.INHERIT)
Update: (too much for a comment) I think you're confused. When you launch a process from a terminal, the process becomes a child of that terminal process, and the stdout is sent to that terminal. When you launch a process from Java, then the process is a child of the Java process, and its stdout goes to Java.
In the first case, there's a terminal showing stdout because you launched it from a terminal yourself, and that's what terminals do with stdout. When launching from Java, however, there wouldn't be a terminal window unless something in the process you launched opened a terminal, and stdout of the process you launched is handed back to you, the programmer, to do with as you will. The equivalent behavior to what you see when launching from a terminal is the Redirect.INHERIT that I already mentioned.
Your problem right now isn't Java. Your problem is not understanding how this "srcds.exe" expects stdin and stdout to be handled. Figure that out, and then come back and ask how to do that with Java.
I'm just guessing now, but you could try reading from the process' stdout and feeding it back into the stdin. Maybe that's what it's expecting? That sounds crazy, though.
you can get the output like this
ProcessBuilder pb = new ProcessBuilder(args);
Process p = pb.start();
//below code gets the output from the process
InputStream in = p.getInputStream();
BufferedInputStream buf = new BufferedInputStream(in);
InputStreamReader inread = new InputStreamReader(buf);
BufferedReader bufferedreader = new BufferedReader(inread);
String line;
while ((line = bufferedreader.readLine()) != null) {
*do something / collect output*
}
I've been struggling with this for a while, but the simplest i guess you could do is by transferring the streams yourself, using some kind of StreamTransfer class, you can say which InputStream gets written to which OutputStream in separate threads to avoid deadlocks.
In this example, i execute ls then cat and manually wire the stdout of ls into the stdin of cat, and then cat's stdout to System.out to print the final result :
public class TestRedirectingStreams {
public static void main(String[] args) throws IOException, InterruptedException {
ExecutorService threads = Executors.newFixedThreadPool(10);
Process echo = Runtime.getRuntime().exec("ls"),
cat = Runtime.getRuntime().exec("cat");
threads.submit(StreamTransfer.transfer(echo.getInputStream(), cat.getOutputStream()));
threads.submit(StreamTransfer.transfer(cat.getInputStream(), System.out));
threads.shutdown();
}
}
class StreamTransfer implements Callable<Void> {
public static final int BUFFER_SIZE = 1024;
private InputStream in;
private OutputStream out;
public static StreamTransfer transfer(InputStream in, OutputStream out) {
return new StreamTransfer(in, out);
}
private StreamTransfer(InputStream in, OutputStream out) {
this.in = in;
this.out = out;
}
#Override
public Void call() throws Exception { // write to streams when thread executes
byte[] buffer = new byte[BUFFER_SIZE];
int read = 0;
while ((read = in.read(buffer)) != -1)
out.write(buffer, 0, read);
in.close();
out.close();
return null;
}
}
If you want to use ProcessBuilder instead the example stays the same, since ProcessBuilder.start() returns the process you can still retrieve the desired streams and transfer accordingly.

Categories