I'm trying to kill off a already running java process using the Name of the .jar file.
It works completely fine when running the command
pkill -9 -f myapp.jar
from terminal but it doesn't work when you run that same command in a ProcessBuilder.
BufferedReader killStream;
String line;
try{
String[] args = new String[] {"pkill", "-9", "-f", " myapp.jar"};
Process proc = new ProcessBuilder(args).start();
killStream = new BufferedReader(new InputStreamReader(proc.getInputStream()));
line = killStream.readLine();
System.out.println(line);
return true;
}catch(Exception e){
e.printStackTrace();
return false;
}
killStream always return 'null'
What am i doing wrong here?
There are a few missing points here, aside from what is mentioned above regarding the passing in of the arguments your code could do with some more refining.
First of all why not use a try with resources clause to make sure that your resources are managed automatically and get always closed correctly?
With this in mind your code would look like:
try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
// code to parse the command's output.
} catch (IOException e) {
// code to handle exceptions
}
Secondly, with the current code your method will always return true even if the pkill command has not run correctly.
Ideally would should wait for the process to terminate using Process#waitFor and then invoke Process#exitValue to retrieve the exit status of the command. Then you should return true or false based on whether the exit code is 0 or anything else.
Finally in order to be a bit more efficient, I would suggest using a StringBuilder to collect and append all of the process's output lines and just printing out that String.
Note that there are even better methods to encapsulate all this procedures making it more generic and re-usable while also using Java 8+ API (like streams, consumers etc etc).
Related
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 am trying to run an exe file while setting some parameters for it like this:
myExePath -ini myIniPath -x myConfigFilePath
When I run it from the command line it works perfectly. But when I try running it from my Java code the process starts but after a while is not responding anymore so I have to forcibly close it. I am using this Java code:
List<String> parameters = new ArrayList<String>();
parameters.add(myexePath);
parameters.add("-ini ");
parameters.add(myIniPath);
parameters.add("-x ");
parameters.add(myConfigPath
ProcessBuilder builder = new ProcessBuilder(parameters);
Process process = builder.start();
try {
process.waitFor();
} catch (InterruptedException e) {
System.err.println("Process was interrupted");
}
Any ideas what I am doing wrong?
Does the exe use stdout, stderr, stdin? You should always read from them or close them. Depending on the implementation and buffer size not reading from them could lead to blocking.
I'm not sure if it helps, but why you use spaces?
e.g.: parameters.add("-x ");
You don't need them.
What you can also try is to put all your parameters in an array and use another constructor of ProcessBuilder which takes an array as argument.
I guess you should first get a reference to the Runtime.
You could do this
Runtime.getRuntime().exec(parameters.toString());
Your string from the parameters list may need a bit formatting.
I have an execute(String cmd) in a jsp script that calls the exec method from the Runtime class.
It works when I call a local command, like a php script stored on the server. for example: /usr/bin/php /path/to/php/script arg1 arg2
So I guess my execute command is ok, since it is working with that.
Now when I try to call lynx, the text-based web browser, it does not work.
If I call it in a terminal, it works fine:
/usr/bin/lynx -dump -accept_all_cookies 'http://www.someurl.net/?arg1=1&arg2=2'
But when I call this from my execute command, nothing happens...
Any idea why?
This is my execute method:
public String execute(String cmd){
Runtime r = Runtime.getRuntime();
Process p = null;
String res = "";
try {
p = r.exec(cmd);
InputStreamReader isr = new InputStreamReader(p.getInputStream());
BufferedReader br = new BufferedReader(isr);
String line = null;
//out.println(res);
while ((line = br.readLine()) != null) {
res += line;
}
p.waitFor();
} catch (Exception e) {
res += e;
}
System.out.println(p.exitValue());
return res;
}
You need to read from the Process' output stream.
Since you're not, the underlying lynx process is likely blocking while writing output, waiting for someone to empty the output stream's buffer. Even if you're going to ignore the output, you need to read it anyway for the process to execute as you'd expect.
As the javadocs of Process say, "Because some native platforms only provide limited buffer size for standard input and output streams, failure to promptly write the input stream or read the output stream of the subprocess may cause the subprocess to block, and even deadlock."
See http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html for some examples of how to handle this.
Edit: in case you are wondering, chances are that when you invoked the PHP script it didn't produce a great deal of output, and so was able to terminate before filling the output buffer and blocking. The lynx command is presumably producing more output and hence hitting this issue.
I solved it.... by calling lynx into a php script, php script that I called from the Jsp script...
It's a shitty solution but at least it works... I still do not really understand why the exec command from Java works that way...
Thanks for your help anyway Andrzej (Czech I guess from the name..? ^_^), somehow you put me on the way!
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);
}
}