How to run commands you can run on terminal in Java - 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();

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).

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 Process stops early even when output is redirected

I have a Java application that calls a tcsh script which in turn calls a perl script in the same directory. If I run this script from the command by typing "runPerlScript.sh", it works completely fine, and generates several output files as it should. However, if I call the script from Java, using the code below:
String[] runCmd = {"/bin/tcsh","-c","/filepath/runPerlScript.sh"};
Process run = Runtime.getRuntime().exec(runCmd);
BufferedReader reader = new BufferedReader(new InputStreamReader(run.getInputStream()));
String line = "";
line = reader.readLine();
System.out.println("\nStarting while.");
while((line)!=null){
System.out.println("Output from script: "+line);
line=reader.readLine();
}
reader.close();
System.out.println("Finished running perl script.");
it prints out the echo statements from my shell script to my console (I'm using NetBeans), but generates only 4 output files (when normally it generates near 50). It seems as if the process is quitting to early, because after these 4 files are generated, an echo statement in my shell script that says "Finished running runPerlScript.sh" prints out to my console. I've tried several different ways to run this script, including ProcessBuilder, but none seem to generate the output files. The code I have above was in fact the only way I was able to generate ANY output, because ProcessBuilder just resulted in hangups. Does anyone know how I can continuously make the script run?
From the Runtime.exec() javadoc:
"Executes the specified string command in a separate process."
Assuming you want to wait for the process to end, you will need to wait for the process to terminate in your main java thread. The best way to do this would be by monitoring the Process returned by ProcessBuilder.start() and wait with Process.waitFor().

Save output of external program call in textfile in 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

Unix Script not working in Java Process Runtime.exec()

I am developing an application in Spring Web MVC where i need to execute some of the linux script..
I am using tomcat version 5.5 for running my project in linux..
My code is looking like this :
Process proc = runtime.exec("sudo cp /var/tmp/mailserverfiles/editinterface.txt /etc/sysconfig/network-scripts/editinterface.txt");
InputStream inputstream = proc.getInputStream();
InputStreamReader inputstreamreader = new InputStreamReader(inputstream);
BufferedReader bufferedreader = new BufferedReader(inputstreamreader);
String line;
while ((line = bufferedreader.readLine()) != null) {
System.out.println("\nOUTPUT = " + line);
}
System.out.print("\nbefore execute6");
try {
if (proc.waitFor() != 0) {
System.err.println("\nexit value = " + proc.exitValue());
}
} catch (InterruptedException e) {
System.err.println("\nERROR = " + e);
}
Here i want to cp a particular file from one location to another using linux script..
But when i am executing this part, i am getting
exit value = 1
as a output.. I have also tried to put this script into .sh file and try to execute that shell script here from Java Code, but i am getting same result..
Can anybody tell me, what should be the reason for this ?
Thanks in advance..
I would guess that sudo is expecting an interactive terminal in order to ask for a password. Since there is no interactive terminal, it prints an error message to stderr and exits with an exit code of 1. You are not reading the error stream, so you won't see any message that it might print.
You will definitely want to read the error stream in any case. Doing so now will help you diagnose what is going wrong at this point.
I assume the user that Tomcat is running under has unrestricted access to sudo? And that it's not being prompted for a password?
It is possible that your search path is weird and that "cp" and "sudo" are not found when you try to execute the command.
Here are some things you could try to track down your problem(s):
Try running the "cp" command without "sudo".
Try giving the full pathname of the command(s). This will avoid search path problems.
By default "sudo" logs failed commands using syslog(3). See if you can find traces in the corresponding logfiles.
Assuming you can run your command from a command line, logged in as the tomcat user - try
ProcessBuilder pb = new ProcessBuilder("/usr/bin/sudo", "cp",
"/var/tmp/mailserverfiles/editinterface.txt",
"/etc/sysconfig/network-scripts/editinterface.txt");
pb.redirectErrorStream(true);
Process proc = pb.start();
... rest of code as before
if things still fail, start debugging. strace should be helpful. e.g. run this shell script
from your java application, and figure out where things fail in the /tmp/trace.txt file:
#!/bin/sh
strace -f sudo cp /var/tmp/mailserverfiles/editinterface.txt /etc/sysconfig/network-scripts/editinterface.txt >/tmp/trace.txt 2>&1
Whilst not directly answering your question, the following will help. You need to read stdout and stderr (to capture all process output), and do this concurrently to prevent blocking of the spawned process. See this answer for more info.

Categories

Resources