I have this program that I am writing that has this method that is supposed to execute a program but does not do anything. The method in question is as follows:
public void findCC_Data(List<String> l7) {
StringBuffer output = new StringBuffer();
Process p;
try {
for(String sql_file: l7) {
String command = "cleartool describe " + sql_file;
p = Runtime.getRuntime().exec(command);
System.out.println("Executing: " + command);
p.waitFor();
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = "";
while ((line = reader.readLine()) != null) {
output.append(line + "\n");
}
if (reader.readLine() == null) {
System.out.println("'reader.readLine()' is equal to null");
}
}
} catch(Exception e) {
e.printStackTrace();
}
System.out.println(output.toString());
}
Does anyone know why the command does not do anything and the reader.readLine() method always returns null?
I am following a tutorial but using the cleartool program instead of the ping program basically. The tutorial is at this URL:https://www.mkyong.com/java/how-to-execute-shell-command-from-java/
Solution
I had the System.out.println(output.toString()) print statement outside of the for loop instead of inside it. Now when I move the SOP statement inside the loop it prints a million plus lines of information on ClearCase version control stuff. To fix put the SOP with the output.toString() inside the loop in the broken code above.
One possibility for a program in (java, python, bash, ...) to do nothing with ClearCase command is if said cleartool command is run within a dynamic view which has been set (cleartool setview).
As I explained before, the cleartool setview command opens a subshell in which commands are supposed to be run, which is not the case here (the java program runs in the main shell)
The other possible cause is that you are reading stdout, not stderr, and somehow this commands returns an error (maybe its execution path is not correct).
thought it would not matter anyway because a method I call before the one in question is supposed to change directories to the dynamic view. It appears it does not work as expected though because the result of the cleartool pwd command is just my desktop
Yes, each cleartool command operates in its own shell. You must set the right execution folder for each Java Process run("cleartool ...") commands, in order for those cleartool commands to start in the right folder.
See "execute file from defined directory with Runtime.getRuntime().exec", although the answer is a bit dated, and that might have changed with Java8.
As the OP noted, the output.toString() print statement was outside of the for loop instead of inside said loop.
You can see additional example in:
"Capturing stdout when calling Runtime.exec"
"No output from Runtime.getRuntime().exec(“ls”)"
Run your command inside a child shell using sh command and redirect the output to nohup, refer nohup and sh command.
once you have the command executed i.e. "nohup cleartool describe " + sql_file;
you can get the error or details from nohup.out file and confirm if there is an issue in executing the command.
Related
I am trying to run a piece of Python code via a Java application. The command when put directly into Command Prompt cd'd to the working directory runs exactly as intended. However, my attempts to use the Runtime and ProcessBuilder classes in conjunction with the Process class has yielded no sign of correct function which would be the creation of a CSV file for every call of the code.
I am running this program using Intellij on Windows 10. I have added each directory I am using to my environmental PATH variable as well as attempting full paths in my commands and just file names. The only source of life I can find is that if I include a .waitFor() method a .isAlive() method will return true before the .waitFor() method is called.
I have searched through various similar questions and concluded that using a ProcessBuilder object is the best way to go and that the biggest issue is probably the structure of my command. However, I have made many iterations and have found nothing that changes the caught error to anything useful.
Here is the privacy augmented code that I have been running, I wrote out the command in full in the process builder as that is the last iteration I have attempted.
for (int y = 1; y < iterator; y++) {
try {
String command =
"C:\\Users\\myName\\AppData\\Local\\Programs\\Python\\Python37\\python C:\\Users\\myName\\IdeaProjects\\projectApplication\\script.py ";
String pythonInputPath = " C:\\Users\\myName\\IdeaProjects\\projectApplication\\bin\\output" + y + ".wav ";
ProcessBuilder pb = new ProcessBuilder(command+Arrays.toString(pythonCommandString).replaceAll("\\s","")+pythonInputPath+Integer.toString(y));
Process p = pb.start();
//Process checks
System.out.println(p.isAlive());
p.waitFor();
System.out.println(p.isAlive());
//Destroying process once complete to ensure smooth iterations
p.destroy();
} catch (Exception ex) {
System.out.println("Problems with python script execution: " + ex);
}
}
They python code takes in a WAV file (pythonInputPath) that is a product of earlier part of the application, an Integer[] that usually includes ~20 values (pythonCommandString), and a single iteration integer (y).
The first call to .isAlive() is true and the second is false as expected however the script normally creates a CSV that should be output to a bin file that exists in the working director and that fails to occur when running from Java. From other examples I expected using the Process builder as opposed to the Runtime stream to work, however, there is no difference in my implementation.
Do not concatenate the program with its arguments. Quoting Oracle ProcessBuilder docs
Each process builder manages these process attributes: a command, a
list of strings which signifies the external program file to be
invoked and its arguments, if any
and
ProcessBuilder pb = new ProcessBuilder("myCommand", "myArg1", "myArg2");
Just use the constructor you use, but pass each argument as a separate string, otherwise the OS will try to find an application that is named as a whole command line you gave, and obviously there is no such program
I am using the process class to run this command
/sdcard/file1.mpg /sdcar/file2.mpg > /sdcard/out.mpg
Here is how I am trying to do it:
Process processx = Runtime.getRuntime().exec(new String[] {"cat","/sdcard/file1.mpg /sdcard/file2.mpg > /sdcard/out.mpg" });
BufferedReader in = new BufferedReader(new InputStreamReader(processx.getInputStream()));
String line = null;
while ((line = in.readLine()) != null) {
System.out.println(line);
}
// Waits for the command to finish.
processx.waitFor();
The command works from terminal but not when I try the above, can anyone see why?
Redirection (>) is not the OS feature. This is a feature of shell. To make it working from java you have to run something like the following:
/bin/sh yourcommand > yourfile
i.e. in your case:
/bin/sh cat /sdcard/file1.mpg /sdcard/file2.mpg > /sdcard/out.mpg
BUT could you please explain me why are you doeing this? Do you understand that this command is exact equivalent of cp /sdcard/file1.mpg /sdcard/file2.mpg /sdcard/out.mpg that can be coded in pure java without running any command line? Unless you have special reasons go on it! Write pure java code when it is possible. It is easier to debug, support and maintain.
There's absolutely no reason to use 'cat' to do this. It's not a supported or encouraged mechanism on Android, and there's no reason to launch a new executable to do what you can easily do in java code, by reading in one file and writing it out to the other.
For the record, you are trying to do a shell redirection, and that will not work since you are not executing a shell.
im using this small code to execute "cat" command and most of shell commands:
String[] cmdline = { "sh", "-c", "cat /sdcard/file1 >> /sdcard/file2" };
try {
Runtime.getRuntime().exec(cmdline);
} catch (Exception s) {
finishAffinity();
}
This is my first question on stackoverflow so I'll try to keep it concise and relevant.
I'm currently creating a Java program that is attempting to call an external program located on the system, in order to do this however I am required to call a shell script that sets up links to the relevant libraries to ensure that the system is linked to these before the external program can be executed.
The issue at hand is that I cannot invoke the shell script through Java, I've researched high and low and am aware that of alternative ways such as the use of the ProcessBuilder class. Unfortunately I'm quite new to the world of trying to invoke command line statements through Java and so I'm stuck for answers.
An example of the code I am using can be found below:
private void analyse_JButtonActionPerformed(java.awt.event.ActionEvent evt) {
// Get project path for copying of Fortran program to folder and execution
String projectPath = Newproject_GUI.getProjectPath();
String sourcePath [] = {"/bin/sh ", "-c ","source ~/set_env_WRF_gnu.sh"} ;
Runtime fortranAnalyser = Runtime.getRuntime();
try {
Process p = fortranAnalyser.exec("cp main.exe " + projectPath);
Process k = fortranAnalyser.exec(sourcePath);
BufferedReader is = new BufferedReader(new InputStreamReader(k.getInputStream()));
String line;
while ((line = is.readLine()) != null) {
System.out.println(line);
}
} catch (IOException ex) {
Logger.getLogger(Analyser_GUI.class.getName()).log(Level.SEVERE, null, ex);
}
}
Process p works fine and does indeed copy main.exe to the intended directory when the method is called. Process k however does not and this is where the issue is.
Thanks in advance.
The issue is "source" is internal command of BASH (you are using "sh" but that is just BASH in the simplified mode). So what you do is:
you spawn new process "sh" and source something there (setting some VARIABLES I guess)
the process ends and all VARIABLES are lost
you spawn another process, but VARIABLES are already gone
I am not sure if you use those variables later on, but according to the script name it is probably setting some. Don't do that like this.
By the way if you only want to execute script in bash, you don't need to source it. To get it's side effects, just execute it with:
String sourcePath [] = {"/bin/sh ", "/home/XYZ/set_env_WRF_gnu.sh"} ;
Please note you cannot use ~ in this case, use Java to get your home dir.
My aim with this project was to have a remote command prompt feel with Java. Using TCP/IP sockets, I was aiming to run a command prompt process on one computer, and virtually transmit all control to the other side. I immediately stumbled over Runtime.getRuntime().exec() and Process objects, etc. I've solved my problem about halfway. With my remote command prompt, I can run a single command, gather the output, and send it back to the other side. The problem is, I can only seem to run one command per command prompt instance. This won't do (with situations where I need to change directory and THEN run a command, etc). I've stripped all socket/networking programming from this situation to show you (and to create an easier testing environment for me).
import java.io.*;
public class testingProgram {
public static void main(String[] args) {
Runtime rt = Runtime.getRuntime();
StringBuilder inputMessage = new StringBuilder();
String resultData;
try {
Process pr = rt.exec("cmd.exe /c net user");
BufferedReader processInput = new BufferedReader(new InputStreamReader(pr.getInputStream()));
BufferedReader errorProcessInput = new BufferedReader(new InputStreamReader(pr.getErrorStream()));
PrintWriter processOut = new PrintWriter(pr.getOutputStream());
while( (resultData = processInput.readLine()) != null ) {
inputMessage.append(resultData + "\n");
}
resultData = inputMessage.toString();
System.out.print(resultData);
} catch(IOException e) {
} //catch(InterruptedException e) {
//}
}
}
I have a lot more, but this is where my problem is. I can customize the command "net user" with a simple variable and message from the socketstream, so that's not my problem. My problem is that I need to create an ongoing command prompt instance, retaining all redirections of the input/output. Basically, I would like to be able to send another command AFTER "net user".
I have gathered and redirected the output stream. I want to be able to do something like:
processOut.write("net user");
I want to be able to use this, have the command prompt run the command, and retain the output (whether it be from the errorStream OR the inputStream).
I just need some more direction on how to go about doing this.
You should look into multi threading. What you basically want is a thread which keeps running and maintaining the rt.
Like this:
String commandLine;
while ((commandLine = System.in.readline()) != 'q') {
Process pc = rt.exec(commandLine);
}
For further reference on multithreading:
http://download.oracle.com/javase/tutorial/essential/concurrency/procthread.html
You problem is that your program terminates after one call.
cheers
You're telling the command interpreter to terminate. Remove the /C after cmd.exe.
cmd /?
Starts a new instance of the Windows command interpreter
CMD [/A | /U] [/Q] [/D] [/E:ON | /E:OFF] [/F:ON | /F:OFF] [/V:ON | /V:OFF]
[[/S] [/C | /K] string]
/C Carries out the command specified by string and then terminates
/K Carries out the command specified by string but remains
...
I want to exceute a simple command which works from the shell but doesn't work from Java.
This is the command I want to execute, which works fine:
soffice -headless "-accept=socket,host=localhost,port=8100;urp;"
This is the code I am excecuting from Java trying to run this command:
String[] commands = new String[] {"soffice","-headless","\"-accept=socket,host=localhost,port=8100;urp;\""};
Process process = Runtime.getRuntime().exec(commands)
int code = process.waitFor();
if(code == 0)
System.out.println("Commands executed successfully");
When I run this program I get "Commands executed successfully".
However the process is not running when the program finishes.
Is it possible that the JVM kills the program after it has run?
Why doesn't this work?
I'm not sure if I'm not mistaken, but as far as I see you're generating the commands but never passing them to the "execute" method... you're executing "".
Try using Runtime.getRuntime().exec(commands) =)
I would like to say how I solved this.
I created a sh script that basically run the command of soffice for me.
Then from Java I just run the script, and it works fine, like this:
public void startSOfficeService() throws InterruptedException, IOException {
//First we need to check if the soffice process is running
String commands = "pgrep soffice";
Process process = Runtime.getRuntime().exec(commands);
//Need to wait for this command to execute
int code = process.waitFor();
//If we get anything back from readLine, then we know the process is running
BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
if (in.readLine() == null) {
//Nothing back, then we should execute the process
process = Runtime.getRuntime().exec("/etc/init.d/soffice.sh");
code = process.waitFor();
log.debug("soffice script started");
} else {
log.debug("soffice script is already running");
}
in.close();
}
I also kill the soffice process by calling this method:
public void killSOfficeProcess() throws IOException {
if (System.getProperty("os.name").matches(("(?i).*Linux.*"))) {
Runtime.getRuntime().exec("pkill soffice");
}
}
Note that this only works in Linux.
I believe you aren't handling quoting correctly. The original sh command line includes double quotes to prevent the shell interpreting the semicolons. The shell strips them off before the soffice process sees them.
In your Java code the shell will never see the arguments, so the extra double quotes (escaped with backslashes) are not needed - and they are probably confusing soffice.
Here's the code with the extra quotes stripped out (and a semicolon thrown in)
String[] commands = new String[] {"soffice","-headless","-accept=socket,host=localhost,port=8100;urp;"};
Process process = Runtime.getRuntime().exec(commands);
int code = process.waitFor();
if(code == 0)
System.out.println("Commands executed successfully");
(Disclaimer: I don't know Java, and I haven't tested this!)
"/Applications/OpenOffice.org\ 2.4.app/Contents/MacOS/soffice.bin -headless -nofirststartwizard -accept='socket,host=localhost,port=8100;urp;StartOffice.Service'"
or simply escaping the quotes will work as well. We feed a command like this to an ant script that ultimately ends up in an exec call like you have above. I would also recommend restarting the process every 500 or so conversions because OOO does not properly free memory (depending on what version you are running).