Save output of external program call in textfile in java - java

I am using Windows!
I want to call a small .exe application from my java command line which is called "saucy.exe". It needs an input file "input.saucy". Both are stored in the correct directory.
When I use the command
Process p = Runtime.getRuntime().exec("saucy input.saucy");
everything works fine and I get an output on the console.
However, when I try to write the output in a file
Process p = Runtime.getRuntime().exec("saucy input.saucy > output.saucy");
nothing happens.
I already found the advice in http://www.ensta-paristech.fr/~diam/java/online/io/javazine.html and tried to tokenize the command manually:
String[] cmd = {"saucy", "input.saucy > output.saucy"};
Process p = Runtime.getRuntime().exec(cmd);
It is still not working. Any advice? It is no option for me to write the output to a file with java code, because its too slow.
Again: I am using Windows (I stress that because I read several hints for Linux systems).

> is a shell command, but you are not using one. try
String[] cmd = { "cmd", "/C", "saucy input.saucy > output.saucy" };

If you are on Java 7 you can use the new ProcessBuilder.redirectOutput mechanism:
ProcessBuilder pb = new ProcessBuilder("saucy", "input.saucy");
// send standard output to a file
pb.redirectOutput(new File("output.saucy"));
// merge standard error with standard output
pb.redirectErrorStream(true);
Process p = pb.start();

Use the getInputStream(), getOutputStream() and getErrorStream() to retrieve the output (or send input).
http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/Process.html

Related

Pipe ("|") doesn't work with ProcessBuilder in Android [duplicate]

I'm trying to use Java's ProcessBuilder class to execute a command that has a pipe in it. For example:
ls -l | grep foo
However, I get an error:
ls: |: no such file or directory
Followed by:
ls: grep: no such file or directory
Even though that command works perfectly from the command line, I can not get ProcessBuilder to execute a command that redirects its output to another.
Is there any way to accomplish this?
This should work:
ProcessBuilder b = new ProcessBuilder("/bin/sh", "-c", "ls -l| grep foo");
To execute a pipeline, you have to invoke a shell, and then run your commands inside that shell.
The simplest way is to invoke the shell with the command line as the parameter. After all, it's the shell which is interpreting "|" to mean "pipe the data between two processes".
Alternatively, you could launch each process separately, and read from the standard output of "ls -l", writing the data to the standard input of "grep" in your example.
Since Java 9, there’s genuine support for piplines in ProcessBuilder.
So you can use
List<String> result;
List<Process> processes = ProcessBuilder.startPipeline(List.of(
new ProcessBuilder("ls", "-l")
.inheritIO().redirectOutput(ProcessBuilder.Redirect.PIPE),
new ProcessBuilder("grep", "foo")
.redirectError(ProcessBuilder.Redirect.INHERIT)
));
try(Scanner s = new Scanner(processes.get(processes.size() - 1).getInputStream())) {
result = s.useDelimiter("\\R").tokens().toList();
}
to get the matching lines in a list.
Or, for Windows
List<String> result;
List<Process> processes = ProcessBuilder.startPipeline(List.of(
new ProcessBuilder("cmd", "/c", "dir")
.inheritIO().redirectOutput(ProcessBuilder.Redirect.PIPE),
new ProcessBuilder("find", "\"foo\"")
.redirectError(ProcessBuilder.Redirect.INHERIT)
));
try(Scanner s = new Scanner(processes.get(processes.size() - 1).getInputStream())) {
result = s.useDelimiter("\\R").tokens().toList();
}
These examples redirect stdin of the first process and all error streams to inherit, to use the same as the Java process.
You can also call .redirectOutput(ProcessBuilder.Redirect.INHERIT) on the ProcessBuilder of the last process, to print the results directly to the console (or wherever stdout has been redirected to).

How to run commands you can run on terminal in Java

So guys I want to execute a command that you can execute on the cmd in my Java program. After doing some study, I thought i found a way to do this. However, my code doesn't work.
My code is
import java.io.*;
public class CmdTest {
public static void main(String[] args) throws Exception {
String[] command = {"ag","startTimes conf.js >> pro.txt"};
ProcessBuilder builder = new ProcessBuilder(command);
builder.directory(new File("./test-java/"));
Process p = builder.start();
}
}
The program executes but produces no output. I tried using other commands like "ls -a", but still no output.
Can someone please help me debug this or suggest a better way of doing this? Thank you
Edit 1: I am executing this on a Mac. If that is necessary for debugging
Edit 2: The usual ls and other commands are working with the solutions that you guys have provided. I however want to use the ag (the_silver_searcher) command in the Java program. When i try that, i get the following error -
Exception in thread "main" java.io.IOException: Cannot run program "ag startTimes conf.js >> pro.txt": error=2, No such file or directory
The existing answers give you the information on how to solve your problem in code, but they don't give a reason why your code is not working.
When you execute a program on a shell, there's significant processing done by the shell, before the program is ever executed. Your command line
String[] command = {"ag","startTimes conf.js >> pro.txt"};
ProcessBuilder builder = new ProcessBuilder(command);
assumes that the command ag is run with the single argument startTimes conf.js >> pro.txt - most likely not what you want to do. Let's go one step further: What if you wrote
String[] command = {"ag","startTimes", "conf.js", ">>", "pro.txt"};
ProcessBuilder builder = new ProcessBuilder(command);
?
This would assume that the ag command knows about the >> parameter to redirect its output - and here is where the shell comes into play: The >> operator is an instruction to the shell, telling it what to do with the output from stdout of the process. The process ag, when started by the shell, never has an idea of this redirection and has no clue about >> and the target file name at all.
With this information, just use the code samples from any of the other answers. I won't copy them into mine for proper attribution.
While there is ProcessBuilder, I've always used Runtime.getRuntime().exec("cmd");
Process Runtime.exec(String)
It returns a Process which you can get the input and output streams of
Even if you stay with the ProcessBuilder, you should still have access to the Process.get<Input/Output/Error>Stream()
You need to read the output of the process by opening an input stream from the process:
try (BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream())) {
System.out.println(reader.readLine()); // process the output stream somehow
}
Additionally you might the read the error stream ( p.getErrorStream()), which I often have done in a separate stream, in Java 8 you can use redirectErrorStream(true) on the ProcessBuilder to automatically add the error stream to the input stream. Of course you can't distinquish anymore from which stream the input comes, but it makes reading easier. If you don't read the input or error stream and the process's buffer becomes full the processes tend to pause until there is enough room in the buffer again.
You can also add
builder.redirectOutput(ProcessBuilder.Redirect.INHERIT);
before the start method which redirects the output to the console.
//"ls" command runs under the "sh" on linux(cmd.exe on windows), so first arg is "sh"
//second arg "-c" tells "sh" which exact command should be executed
//"ls" is actual command
//"startTimes" as I understand is a file or directory, it is arg for "ls" command
//"conf.js" is second arg for "ls" command
new ProcessBuilder("sh", "-c", "ls", "startTimes", "conf.js")
//set working dir for "sh" process"
.directory(new File("./test-java/"))
//output will be written to "pro.txt" in working dir of "sh" process
.redirectOutput(new File("./test-java/pro.txt"))
.start();

run a .sh file using java

I want to run a .sh file using java. I want a terminal to be opened and then I can execute another commands in the same terminal and finally destroy it.
I already used ProcessBuilder but I could not accomplish this.
My piece of code:
ProcessBuilder pb = new ProcessBuilder("/home/omar/ros_ws/baxter2.sh");
Process p = pb.start();
This method used to work in another code, but I don't know why it's not working in mine.
Thanks in advance
How do you know that it doesn't execute? Maybe you just aren't seeing its result. You should get p.getInputStream() after executing and print in your console, like:
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = null;
while ((line = reader.readLine()) != null)
{
System.out.println(line);
}
Also if you're using jdk 7+, try:
pb.redirectOutput(Redirect.INHERIT);
pb.redirectError(Redirect.INHERIT);
Process p = pb.start();
Does your program output an error, or is your program not interacting with the file?
I would suggest trying the directory method within ProcessBuilder.
Process p = null;
ProcessBuilder pb = new ProcessBuilder("baxter2.sh");
pb.directory("/home/omar/ros_ws");
p = pb.start();
If this doesn't work, you should also look into user permissions for the file that you're trying to access.
I think you should grant the .sh file the executable permission to the OS user used to run the java program by using the below command.
chmod u+x baxter2.sh

Program execution in java

I am trying to open an exe file, specificly the IndriRunQuery.exe which is one of the tools that offers the Lemur Indri package. When i use the command prompt i write the following command:
IndriRunQuery Queries.txt
With this, the editting of the queries that are included in Queries.txt (which is passed as a parameter in the above command) is starting.
Then after a descent amount of time has passed ,i write the following in order to save the results that are produced in a file named Results.txt:
IndriRunQuery Queries.txt >Results.txt
My problem is that every time that i want to edit a file which contains queries
i need to do the same steps. i have 20 different query files to edit. I am trying to find a way to do it by using a java program but i can not figure it out.
I have used these lines of code but it doesnot work at all.
Can anyone help me out with this?
ProcessBuilder builder = new ProcessBuilder("C:\\Program Files\\Indri\\Indri 5.8\\bin\\IndriRunQuery.exe",
"C:\\Users\\Πετρής\\Desktop\\TitlesRel.txt");
builder.start();
ProcessBuilder builder2 = new ProcessBuilder("C:\\Program Files\\Indri\\Indri 5.8\\bin\\IndriRunQuery.exe",
"C:\\Users\\Πετρής\\Desktop\\TitlesRel.txt",">C:\\Users\\Πετρής\\Desktop\\resultsexample3.txt");
builder2.start();
The correct syntax is as below:
// Create ProcessBuilder.
ProcessBuilder p = new ProcessBuilder();
// Use command "notepad.exe" and open the file.
p.command("notepad.exe", "C:\\file.txt");
p.start();
Or
Process p = Runtime.getRuntime().exec("cmd /c start " + file.getAbsolutePath());

Java: Run diskpart script and read output

I'm writing a java tool that needs to retrieve output returned by diskpart. Diskpart is called using the /s option with a specified script. I'm using Windows 7 with the lowest possible UAC settings.
ProcessBuilder builder = new ProcessBuilder("cmd.exe", "/c", "diskpart", "/s", "c:\\dps.txt");
Process p = builder.start();
p.waitFor();
InputStream ins = p.getInputStream();
System.out.println(ins.available()); // Output: 0
Using the following line instead of the above produces an empty output file c:\dps_out.txt
ProcessBuilder builder = new ProcessBuilder("cmd.exe", "/c", "diskpart", "/s", "c:\\dps.txt", ">>", "c:\\dps_out.txt" );
When calling diskpart using this method, there seems to be nothing to read from standard output, since Process.getInputStream() and the Windows output redirection both access standard output and fail to read data.
Calling diskpart directly requires elevation.
ProcessBuilder builder = new ProcessBuilder("diskpart", "/s", "c:\\dps", ">>", "c:\\dps_out" );
Exception in thread "main" java.io.IOException: Cannot run program "diskpart": CreateProcess error=740, The requested operation requires elevation.
How do I properly run the diskpart script and read its output from within the java tool?
What is your question?
This is from DiskPart's manifest.
<requestedPrivileges>
<requestedExecutionLevel
level="requireAdministrator"
uiAccess="false"
/>
</requestedPrivileges>
Cmd doesn't require admin access so works (it's set AsInvoker). Calling DiskPart direct won't work due to the manifest - requireAdministrator.

Categories

Resources