I need to run the Oracle EXP command through a Java program and print somewhere the command output.
The EXP command is correct, the dump file is created correctly when I execute my Java code, but I'm experiencing some issues to get the output.
This is an snippet very similar to the one I'm using to read the output:
String line;
String output = "";
try {
Process p = Runtime.getRuntime().exec(myCommand);
BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
while ((line = input.readLine()) != null) {
output += (line + '\n');
}
input.close();
}
catch (Exception ex) {
ex.printStackTrace();
}
System.out.println(output);
As I said, the command is correctly executed (verified through the generated dump file), but nothing appears on my console and my Java programs doesn't terminate either.
The same code works perfectly if I use another command, as "ls -l" instead of "exp ...".
Maybe exp is writing to standard error output rather than standard output.
Try to use p.getErrorStream() instead of getInputStream()
As a_horse_with_no_name said, it might be that the error stream buffer is full and thus is blocking the programm execution.
Either try to start a Thread to also read the error stream or use the ProcessBuilder class to redirect the error stream to stdout (which you already read).
Related
I have an application that calls a java test class in a specified location of my PC. The path is hard-coded for now, and I checked that it worked by executing it from the command line (in case you want to see it: java -cp C:\Users\user\Documents\workspace\test\build\test.jar org.junit.runner.JUnitCore us.test.DynamicWebserviceInvocationTest), so I know that the command works fine.
The thing is, when I do Runtime.getRuntime().exec(command), if I try to log the resulting InputStream and ErrorStream of its resulting process, the program stucks. I tried with exitValue() and waitFor(), but the first throws an incompletition error and the second also gets stuck. The weird thing is that if I don't touch anything of this (the streams, or using the functions), the program has no problem ending.
So my question is: Why could this be? The next step is to build the command with given parameters, but if I can't see the resulting inputs I can't be completely sure if the tests are running or not.
The code, in case you want to see it:
Runtime runtime=Runtime.getRuntime();
logger.debug("Attempting to execute the test {} at path {}",classpath,applicationLocation);
String command="java -cp C:\\Users\\user\\Documents\\workspace\\test\\build\\test.jar org.junit.runner.JUnitCore us.test.DynamicWebserviceInvocationTest";
Process process=runtime.exec(command);
BufferedReader stdInput = new BufferedReader(new
InputStreamReader(process.getInputStream()));
BufferedReader stdError = new BufferedReader(new
InputStreamReader(process.getErrorStream()));
System.out.println("Here is the standard output of the command:\n");
String s = null;
while ((s = stdInput.readLine()) != null) {
System.out.println(s);
}
System.out.println("Here is the standard error of the command (if any):\n");
while ((s = stdError.readLine()) != null) {
System.out.println(s);
}
You absolutely must read both streams in separate threads. (Read the Javadoc of the Process class). If you wait for the end, or read first one stream before the other it can happen that the output buffer of the command fills up and it will block (on stdout or stderr, depending on what you read first). Normally you use waitFor() in the current thread and have background thread draining the outputs (this also allows detecting end of child process without polling).
If you want to use only one (additional) thread you can redirect stderr to stdout. If you want to avoid to read the streams at all, you can set the
ProcessBuilder features inheritIO(). This allows the stream to be written to the existing output and so you do not need a thread to read independently.
There are BTW various libararies which offer exec tools (for example Apache Commons Exec has some streams) which offer active stream draining, logging or pumping for Process.
In addition to that it might also be a good idea to first close stdin, in case the command waits for input: p.getOutputStream().close();
Make sure you close the 2 streams:
String command="java -cp C:\\Users\\user\\Documents\\workspace\\test\\build\\test.jar org.junit.runner.JUnitCore us.test.DynamicWebserviceInvocationTest";
Process process=runtime.exec(command);
BufferedReader stdInput = new BufferedReader(new
InputStreamReader(process.getInputStream()));
BufferedReader stdError = new BufferedReader(new
InputStreamReader(process.getErrorStream()));
// read the output from the command
System.out.println("Here is the standard output of the command:\n");
String s = null;
while ((s = stdInput.readLine()) != null) {
System.out.println(s);
}
stdInput.close();
// read any errors from the attempted command
System.out.println("Here is the standard error of the command (if any):\n");
while ((s = stdError.readLine()) != null) {
System.out.println(s);
}
stdError.close();
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.
I am using below code to run SFTP command through Jsch:
public void putfile(){
try {
String command="winscp /script=D:\\command.txt" ;
System.out.println(command);
Runtime rt=Runtime.getRuntime();
rt.exec(command);
}
catch(Exception e) {
System.out.println("Exception in index.jsp:"+e.getMessage());
}
}
I am putting sample.zip from local machine to Unix Server,
The command.txt contains:
option confirm off
open sftp:User:password#IP
get G:\sample.zip /MyFolderLocation/
exit
Its working fine but i am not getting any exception whenever the SFTP process fails.Is there any way to handle it?
There are two common ways to detect whether a subprocess you ran encountered an error:
check its exit code,
see if it writes any error messages to standard output or standard error.
I don't know whether WinSCP sets an exit code in the event of an error, or writes a message to standard output or standard error, but it should do at least one of them. (It may even do both, which is what I'd expect all well-behaved processes to do.) You'll just have to try out WinSCP and see what happens.
I'd also recommend using a ProcessBuilder instead of Runtime.getRuntime().exec(...) to run the command. If nothing else, this allows you to redirect standard error into standard output so you only have one stream to read from.
Here's what your code looks like after I've modified it to use a ProcessBuilder, get the process's exit code and read the output from the command into a string:
public void putfile() {
try {
ProcessBuilder builder = new ProcessBuilder("winscp", "/script=D:\\command.txt");
builder.redirectErrorStream(true);
Process process = builder.start();
// read output from the process
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
StringBuilder outputBuilder = new StringBuilder();
String line;
do {
line = reader.readLine();
if (line != null) { outputBuilder.append(line).append('\n'); }
} while (line != null);
reader.close();
String output = outputBuilder.toString();
// inspect output for error messages.
int exitCode = process.waitFor();
// see if exit code is 0 (success) or != 0 (error)
}
catch(Exception e) {
System.out.println("Exception in index.jsp:"+e.getMessage());
}
}
Of course, reader should be closed in a finally block. For clarity I haven't bothered doing this in the code above.
Note that when running a subprocess in Java you should always read the subprocess's output, even if you don't care about its contents. If you don't, the buffer that the output gets written into may fill up, which will cause the subprocess to hang if it wants to write any more.
See WinSCP FAQ How do I know that script completed successfully?
You can tell the result of script by WinSCP exit code. Code 0
indicates success, while 1 indicates an error. For more details refer
to scripting documentation.
Batch script (specified using /script or /command command-line switches) terminates with code 1 immediately once any error occurs.
To find out why the script failed, inspect session log.
For an example see guide to transfer automation.
I have my code below. I am trying to run my ruby script and get the standard out, I don't really need standard error in this case. For some reason, I could not get any output at all in my production host, and I only get empty string. The same code works fine in my desktop. If I run my ruby script myself, I could get output from it. My ruby script only has a puts statement for now. Any one know the reason? Is it that I need to some kind of block to wait for the ruby script to finish?
ProcessBuilder processBuilder = new ProcessBuilder();
processBuilder.command("ruby", "tests.rb");
Process process = processBuilder.start();
BufferedReader bufferReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
StringBuilder output = new StringBuilder();
String line;
while ((line = bufferReader.readLine()) != null) {
System.out.println("Line is: " + line);
output.append(line + "\n");
}
bufferReader.close();
return output.toString();
I have redhat machine running zsh.
You need to close the process's output stream (its standard input), and you should probably merge the output and error streams. You might think you don't want them both but you might be wrong, and if the process produces enough unread error output it will stall.
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);
}
}