I need to run a couple of other programs from my own Java program, basically I need to run these command line statements.
svn log --xml -v > svn.log
and
java -jar example.jar arg1 arg2
and I need to use the text outputs written to the console from these programs in my own program. I've tried Runtime.getRuntime().exec() with the svn, but it doesn't seem to be doing anything because it doesn't make a svn.log file. Also both programs need to be called in different places, the svn line needs to be called from inside one folder and the java line needs to be called from another.
Any ideas on how to go about this? If this is not possible in Java, is there a way to do it in C#?
Thanks
Here:
ProcessBuilder processbuilder
try
{
processbuilder.directory(file);
processbuilder.redirectErrorStream(true);
process = processbuilder.start();
String readLine;
BufferedReader output = new BufferedReader(new InputStreamReader(process.getInputStream()));
// include this too:
// BufferedReader output = new BufferedReader(new InputStreamReader(process.getErrorStream()));
while((readLine = output.readLine()) != null)
{
m_Logger.info(readLine);
}
process.waitFor();
}
I've used something similar. You'll actually want to do something with the readLine. I just copied and pasted from code where I didn't care what it said.
The redirection > (like the pipe |) is a shell construct and only works when you execute stuff via /bin/sh (or equivalent). So the above isn't really going to work. You could execute
/bin/sh -c "svn log --xml -v > svn.log"
and read svn.log.
Alternatively, you can read the output from the process execution and dump that to a file (if you need to dump it to a file, or just consume it directly as you read it). If you choose this route and consume stdout/stderr separately, note that when you consume the output (stdout), you need to consume stderr as well, and concurrently, otherwise buffers will block (and your spawned process) waiting for your process to consume this. See this answer for more details.
instead of piping in your command, just let it print to standard output and error output. You can access those streams from your process object that is returned from exec.
For the svn stuff use java SVNKit API.
Seeing your two commands, why don't you do it directly from Java, without executing ? You could use SVNKit for the svn part, and include directly the jars in your classpath.
Try this
public static void main(String[] args) {
try {
// Execute a command with an argument that contains a space
System.out.println(args[0]);
String[]commands = new String[]{"svn", "info", args[0]};
Process process = Runtime.getRuntime().exec(commands);
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
StringBuilder builder = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
builder.append(line);
builder.append(System.getProperty("line.separator"));
}
String result = builder.toString();
System.out.println(result);
}catch(Exception e){
System.out.print(e);
}
}
Related
I'm trying to start some .jar inside an .jar using this code: (I'm trying with craftbukkit server right know)
Runtime rt = Runtime.getRuntime();
Process p = rt.exec("java -jar craft.jar");
BufferedReader out = new BufferedReader(new InputStreamReader(p.getInputStream()));
BufferedWriter in = new BufferedWriter(new OutputStreamWriter(p.getOutputStream()));
this.running = true;
while(this.running){
String line;
if((line = out.readLine()) != null){
System.out.println(line);
}
}
The problem is, it work for a moment, but after a while it stops outputting or just print '>' as show in the image below. How can I fix this? **Plus, Which is the correct way to send commands to the bukkit server?
Thanks!
When using a Process in Java, it is crucial to read stdout and stderr in two independend threads (your while loop). Otherwise the child process can lock up waiting for the filled buffer to be drained.
With Java 7 you can actually redirect stderr to stdout, and possibly redirect the resulting stream to the parents stdout. With older versions you need to attach the seperate threads.
Besides: you should not use the "single string" variant of exec, but specify the args as arrays. This is safer (less vulnerable to parsing problems).
(But I am not sure if this is your actual problem. Maybe you should dump the error stream and see if it helps)
I do it like that:
#Override
public void run(){
// ...
BufferedReader stdInput = new BufferedReader(new InputStreamReader(proc.getInputStream())); //of course proc is an instance of Process, and it's set up
while(true){
String line = stdInput.readLine();
if(line == null) break; //this is essential, when process terminates, line gets null
System.out.println(">"+line);
}
// ...
}
Give it a try.
(Technically it's similiar how you did, but it works for me so i share it)
I'm trying to execute a script from Java program:
public class TestCommandLine
{
public static void main (String[] args)
{
String PATH = "/path/programs/";
String command = PATH + "name_programs param1 param2";
executeCommand (command);
}
private static String executeCommand (String command)
{
StringBuffer output = new StringBuffer();
String line = "";
Process p;
try {
p = Runtime.getRuntime ().exec (command);
p.waitFor ();
BufferedReader reader = new BufferedReader (new InputStreamReader (p.getInputStream ()));
while ((line = reader.readLine ()) != null) {
output.append (line + "\n");
}
}
catch (Exception e) {
e.printStackTrace ();
}
return output.toString ();
}
}
there is not error, but the program does not run. I also try others solutions from stackoverflow but all of them didn't work
If you'd given your actual command to start with, this would have been much quicker.
You cannot use Process.exec to run shell-interpreted commands. Instead it executes programs directly. Thus input/output redirection (|, >, etc.) is not possible.
If you actually read the stderr (getErrorStream()) output it would probably be along the lines of "invalid argument: >".
You will either have to:
Redirect the output in Java. Read from the process's stdout (getInputStream()) and write to a FileOutputStream of some kind.
Execute a shell instead of your command directly. For example /bin/sh -c "command arg > file". The quoted section must be passed to sh as a single argument. In this case you wouldn't be able to see anything in stdout, and would have to open and read the file you just wrote to. The first option is probably more sensible.
And as pointed out elsewhere, unless your expecting a very small amount of output, you shouldn't wait for the command to exit before consuming the streams.
The only time I've done it I've used something like this:
Process p = Runtime.getRuntime().exec("foo.exe");
Have you tried that? If so, what was the error you got back?
Your command is producing output that you want to read, but you refuse to read any of it until the command has finished producing it all and has exited (not calling getInputStream() until after waitFor()).
If your command doesn't produce much output, this is OK, Java can buffer it. But if your command produces a lot of output, Java can't buffer it all, and the command gets blocked.
The operating system won't let the command write any more output because Java's buffer is full and you haven't instructed Java to empty it. So the program is blocked, and Java's waitFor() will never come back.
To solve your problem, you should call getInputStream() immediately after getting the Process object back from exec(), and you should create a new Thread that is responsible for reading the command output into your StringBuffer.
You should then waitFor() the process to finish, to see if it exited successfully, and then you can wait for the thread to get to the end of the inputstream and finish - at that point, it is safe to read through the StringBuffer with the full output from your command.
Can any body help me with how to compile a bash script as part of a java program. I am writing a simple java program that i want to use to invoke bash script commands.
my java code looks like the following:
try{
Process p = Runtime.getRuntime().exec("myscript.sh");
BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = null;
while ((line = in.readLine()) != null){
System.out.println(line);
}
}
catch(IOException e){
System.out.println(e.getMessage());
}
and the "mysrcipt.sh" file is a simple script that contains the following lines
!/bin/bash
echo "enter your input followed by [ENTER]:"
read -e choice
echo $choice
My problem is, the program waits for an input at the read command in the script even if i enter multiple lines and press enter several times.
You can use:
Process p = Runtime.getRuntime().exec("bash_script.sh");
BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = null;
while ((line = in.readLine()) != null) {
// use bash script line output
}
It would be helpful to see some code showing what you're trying to accomplish.
Executing bash script in Java can be done using something like the following...
Runtime runtime = Runtime.getRuntime();
Process process = runtime.exec("YOUR COMMAND STRING");
List<String> lines = IOUtils.readLines(process.getInputStream());
Runtime.exec() is what you need to execute your bash script, but be aware there are a few pitfalls. I found this to be a good article when starting to call external scripts.
It is written for a windows platform, but a lot of what is discussed is relevant to *nix as well.
See also this question.
I'm making an update function for my project, it's working great, until i want it to restart, basically I download the new file and replace it with the old one, and then i want to run it again, now for some reason it doesn't wna run, and i don't get any error...
Here is the complete update class:
http://dl.dropbox.com/u/38414202/Update.txt
Here is the method i'm using to run my .jar file:
String currDir = new File("(CoN).jar").getAbsolutePath();
Process runManager = Runtime.getRuntime().exec("java -jar " + currDir);
It's not clear to me, why do you need to run the jar with a call to exec() . Given that you need to run the code in the .jar file from a Java program, you could simply run the main() method as defined in the jar's manifest, and capture its output - wherever that is.
Using exec() is OK when you need to call a program from the underlying operating system, but there are easier ways to do this if both the caller and the callee are Java programs.
Now, if your jar is gonna change dynamically and you need to update your program according to a new jar, there are mechanisms for reloading its contents, for instance take a look ath this other post.
The JavaDocs for the Process class specifically point out that if you don't capture the output stream of the Process and promptly read it that the process could halt. If this is the case, then you wouldn't see the process that you started run.
I think you have to capture the stream like this :
BufferedReader stdInput = new BufferedReader(new InputStreamReader(runManager.getInputStream()),8*1024);
BufferedReader stdError = new BufferedReader(new InputStreamReader(runManager.getErrorStream()));
// read the output from the command
String s = null;
System.out.println("Here is the standard output of the command:\n");
while ((s = stdInput.readLine()) != null) {
System.out.println(s);
}
The exec function doesn't automatically lookup into the PATH to start a process, so you have to pass the complete path for the java binary.
You can do that by using the java.home system property, see this answer: ProcessBuilder - Start another process / JVM - HowTo?
No one here seemed to help me, so I went to ask my friend and I had it almost right. It abiously required the string to be an array.
solution:
String[] cmd = {"java", "-jar", currDir};
try {
Runtime.getRuntime().exec(cmd);
} catch (IOException e1) {
e1.printStackTrace();
}
How can I write a program in Java that will execute another program? Also, the input of that program should be given from our program and the output of that program should be written into a file.
This is my small set of code to get its output:
Process p = Runtime.getRuntime().exec("C:\\j2sdk1.4.0\bin\\helloworld.java");
BufferedReader input =
new BufferedReader(new InputStreamReader(p.getInputStream()));
while ((line = input.readLine()) != null)
System.out.println(line);
input.close();
This was my set of code but this throws an IOException.
The API that Java offers for this is the ProcessBuilder. It is relatively straightforward to set working directory and pass parameters.
What is a little tricky is passing STDIN and reading STDERR and STDOUT, at least for non-trivial sizes thereof, because you need to start seperate threads to make sure the respective buffers get cleared. Otherwise the application that you called might block until it can write more output, and if you also wait for that process to finish (without making sure that STDOUT gets read), you will deadlock.
You can use java.lang.Process and java.lang.ProcessBuilder. You interact with the input/output of the process using getInputStream/getOutputStream/getErrorStream.
However, there's an Apache Commons library called Exec which is designed to make all of this easier. (It can normally get quite hairy when it comes to quoting command line parameters etc.) I haven't used Exec myself, but it's worth checking out.
When you only want to start other programms, you can use the exec method like this:
Runtime r = Runtime.getRuntime();
mStartProcess = r.exec(applicationName, null, fileToExecute);
StreamLogger outputGobbler = new StreamLogger(mStartProcess.getInputStream());
outputGobbler.start();
int returnCode = mStartProcess.waitFor();
class StreamLogger extends Thread{
private InputStream mInputStream;
public StreamLogger(InputStream is) {
this.mInputStream = is;
}
public void run() {
try {
InputStreamReader isr = new InputStreamReader(mInputStream);
BufferedReader br = new BufferedReader(isr);
String line = null;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
exec:
public Process exec(String command, String envp[], File dir)
#param command a specified system command.
#param envp array of strings, each element of which
has environment variable settings in format
<i>name</i>=<i>value</i>.
#param dir the working directory of the subprocess, or
<tt>null</tt> if the subprocess should inherit
the working directory of the current process.
Please do not edit your question so that it does not fit the original answers anymore.
If you have follow-up question, clearly mark them as such, or ask them as a seperate questions, or use comments or something.
As for your IOException, please give the error message it shows.
Also, it seems as if you are trying to run a ".java" file directly. That will not work. The methods described here are to launch native binary executables. If you want to run a ".java" file, you have to compile it to a class, and the invoke that class' main method.
What platform are you in?
If you are on *nix you can type:
java MyProgram | myexternalprogram > myfilename.txt