Runtime.exec() to bash javac error - java

I'm using Runtime.exec() to run a shell script in a Java program.
The script basically compiles a java program and runs it and goes something like:
./run2.sh "/Users/user/Desktop/Test.java" "Test" "/Users/user/Desktop/"
my parameters in general are the absolute path of the java file, class name and directory where the supposedly compiled class file is
my script is simply
javac "$1"
cd "$3"
java "$2"
I've tried running the resulting command in my Terminal and it works fine. however when the java program runs it, I get and error:
javac: invalid flag: "/Users/user/Desktop/Test.java"
What should I do? I've tried every possible script I can find on the internet (*edit: and I can think of, of course)
(*edit: execute statement)
// some code here...
String[] outFile = translate.translate();
try {
String params = "";
for(String sss: outFile) {
String tmp = "\"" + sss + "\"";
params += tmp + " ";
}
String command = "./run2.sh "+params;
System.out.println(command);
Process proc = Runtime.getRuntime().exec(command);
} //respective catch
the first line, String[] outFile = translate.translate() returns an array Strings of my supposedly parameters

Your mistake is including quote characters in the command string that you are passing to exec(). The exec() method does NOT know how to deal with quotes or other "shell language" stuff. You would be better off trying to execute the command something like this:
Runtime.getRuntime().exec(new String[]{command, arg1, arg2, arg3});
where the command and arguments strings DO NOT have quotes around them.

Related

How to escape java special characters and run Linux commands

I'm writing a java program to find specific files(files with special permissions and by file type) within the directory. The following command executes properly since there aren't any special characters.
find /home/Cnf271/Desktop/ -perm -4000 ;
Now if i try to execute the following command using my java program, terminal doesn't give a proper result.
find /home/Cnf271/Desktop/ -name "*.txt" -perm -4000 -exec ls -ldb {} \;
Java Program,
//
..
System.out.print("Please enter directory path: ");
fileDirectory = scan.next();
System.out.print("Please enter file type (txt/pdf): ");
fileType = scan.next();
filetypecmd = " \"*." +fileType+ "\" ";
System.out.println(filetypecmd);
String cmd = "find "+fileDirectory+ " -name "+filetypecmd+" -perm -4000" ;
Runtime run = Runtime.getRuntime();
Process process = run.exec(cmd);
BufferedReader buffer = new BufferedReader(new InputStreamReader(process.getInputStream()));
String space = "";
while ((space=buffer.readLine())!=null) {
System.out.println(space);
..
//
Program works fine.however, String cmd command doesn't give me a proper result because linux command is wrapped with special characters.How do I execute the following command in my java program.
find /home/Cnf271/Desktop/ -name "*.txt" -perm -4000 -exec ls -ldb {} \;
Thanks.
Elements that need to be quoted (or escaped special characters) for a Linux command shell do not need to be quoted when being executed by Runtime.exec() (they do not need to be protected from the shell).
In your code, remove the extra quotes on the wildcard search parameters:
String filetypecmd = " *." + fileType + " ";
I tested this and was able to run your code correctly on Linux, but I had to remove your -perm -4000 parameters to get results in my case. I received no results with the extra quotes around "*.txt" but all was well without them.
By the way, you can also use a Scanner to collect the results:
Scanner results = new Scanner(process.getInputStream());
while (results.hasNextLine())
{
System.out.println(results.nextLine());
}

Execute cmd script with double quotes

Im trying to execute a Process with multiple parameters but they have double quotes "..." .
This is how I build the script:
public void capture(String from, String to, String outputFile)
This method will run the command, it takes the 3 parameters which are given here:
capture("0", "100", "C:\\Program Files\\myProgram\\file.txt")
So the full built command looks like this:
String command = "\"C:\\Program Files (x86)\\otherProg\\prog.exe\" /dothis "
+ from + " " + to + " \"" + outputFile + "\"";
To see it clearly, this is the visual output of the command:
"C:\Program Files (x86)\otherProg\prog.exe" /dothis 0 100 "C:\Program Files\myProgram\file.txt"
Ok, and then I execute it like this:
String[] script = {"cmd.exe", "/c", command};
Process p = Runtime.getRuntime().exec(script);
And at this point nothing happens.
The command doesnt get executed, however if I take the output:
"C:\Program Files (x86)\otherProg\prog.exe" /dothis 0 100 "C:\Program Files\myProgram\file.txt"
Copy-paste it in CMD the command DOES get executed (and i get the expected output).
I have tried building the command like this but same effect happens.
The only possible way to run that command is to do it like this:
"C:\Program Files (x86)\otherProg\prog.exe" /dothis 0 100 C:\Folder\myProgram\file.txt
without the quotes on last parameter and of course, without spaces in the route.
What is the solution to this?
Update 1:
Also tried script = script.replace("\n","").replace("\t","") and neither works.
Update 2:
Just tried building the process like this:
Process p = Runtime.getRuntime().exec(
"\"C:\\Program Files (x86)\\otherProg\\prog.exe\" /dothis 0 100 \"C:\\Program Files\\myProgram\\file.txt\"");
Passing the escaped command straight to the process does work, but why doesnt it work when they are parameters and building string with them?
SOLVED THANKS TO Tim Biegeleisen below
As he mentioned, there is a problem for java to make a difference between command and parameter and when to run multiple commands, to solve this do the next:
String command = "cd \"C:\\Program Files (x86)\\otherProgram\\\" & program.exe /capture "+from+" "+to+" \""+outputFile+"\"";
& does it work.
I am posting this mainly for informational purposes. Consider the following code:
Process p = Runtime.getRuntime().exec("cmd /c start cmd.exe echo Hello World");
This will indeed cause a Command Prompt to appear at my home (default) directory, but it will not actually execute the echo command. In fact, the following will do the same:
Process p = Runtime.getRuntime().exec("cmd /c start cmd.exe blah blah blah");
So it seems that Java is ignoring everything which comes after the cmd.exe. My explanation for this is that the actual command is start, and the parameter to that command is cmd.exe. In other words, once Java has launched the Command Prompt, it has already used the parameter, and everything else is ignored.
This observation is consistent with your findings that the following works:
Process p = Runtime.getRuntime().exec(
"\"C:\\Program Files (x86)\\otherProg\\prog.exe\" /dothis 0 100 \"C:\\Program Files\\myProgram\\file.txt\"");
In this case, the command is prog.exe, and what comes after it are the parameters. However, if you had tried piping your command into Command Prompt and running from there, then it would not have worked.
So it seems that using Runtime.getRuntime().exec() allows you to execute one process from Java, but not two of them. This makes sense, since Java can execute a process, but the API does not allow it to launch a second process from the first one.
Try to use the process builder and / or seperate your arguments
Process Builder
ProcessBuilder pb = new ProcessBuilder("\"C:\\Program Files (x86)\\otherProg\\prog.exe\"", "/dothis ", "from + " " + to + " \"" + outputFile + "\"");
Process p = pb.start();
Runtime
Runtime.getRuntime().exec(new String[]{"\"C:\\Program Files (x86)\\otherProg\\prog.exe\"", "/dothis ", "from + " " + to + " \"" + outputFile + "\""});

Source command not working through Java

From last day, I have been trying to execute a command on Terminal (MAC) using JAVA but whatever I do nothing is working.
I have the following 2 commands that I want to execute and get the output back in JAVA
source activate abc_env
python example.py
Till now, I have tried the following methods without any output
String[] command = new String[] { "source activate abc_env", "python example.py"};
String result = executeCommands(command);
Here is my executeCommands method
private static String executeCommands(String[] command) {
StringBuffer output = new StringBuffer();
Process p;
try {
for(int i=0; i< command.length;i++)
{
p = Runtime.getRuntime().exec(command[i]);
p.waitFor();
BufferedReader reader =
new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = "";
while ((line = reader.readLine())!= null) {
output.append(line + "\n");
}
System.out.println("Error output: " + p.exitValue());
System.out.println("Output:" + output);
}
} catch (Exception e) {
e.printStackTrace();
System.out.println("Here");
}
return output.toString();
}
This gives me the following exception
Cannot run program "source": error=2, No such file or directory
I searched online and people say that source won't work like this and I should change the command to
String[] command = new String[] { "bash -c 'source activate abc_env'", "python example.py"};
Now, I donot get the exception but the command still does not work and it returns '2' as exitValue()
Then I tried to execute the commands as a script
#!/bin/bash
source activate abc_env
python example.py
I get the following exception when I read the .sh file as string and pass it to command
Cannot run program "#!/bin/bash": error=2, No such file or directory
So, my question is how to run the source command followed by python command properly through Java ? My final goal is execute some python from Java.
EDIT1:
If I try the following command and print the output stream
String[] command = {
"/bin/bash",
"-c",
"source activate cvxpy_env"
};
executeCommand(command));
Output Stream:
ExitValue:1
ErrorOutput:/bin/bash: activate: No such file or directory
If I try the same command but with single quotes around 'source activate abc_env'. I get the following output
ExitValue:127
ErrorOutput:/bin/bash: source activate cvxpy_env: command not found
Solution:
String[] command = {
"/bin/bash",
"-c",
"source /Users/pc_name/my_python_library/bin/activate abc_env;python example.py"
};
According to the Javadoc, Runtime.exec(String) breaks the command into the command-args list using a StringTokenizer, which will probably break your command into:
bash
-c
'source
activate
abc_env'
Which is obviously not what you want. What you should do is probably use the version of Runtime.exec(String[]) that accepts a ready list of arguments, passing to it new String[] {"bash", "-c", "source activate abc_env"}.
Now, to get an idea why it's not working, you should not only read from its stdout but also from stderr, using p.getErrorStream(). Just print out what you read, and it will be a great debugging aid.
Re: your edit. Now it looks like it's working fine, as far as Java and bash are concerned. The output "activate: No such file or directory" is probably the output from the successful run of the source command. It just that source can't find the activate file. Is it in the working directory? If not, you probably should have "cd /wherever/your/files/are; source activate cvxpy_env". Oh, and if your python script depends on whatever side-effects the source command has, you probably have to execute it in the same bash instance, that is:
String[] command = {
"/bin/bash",
"-c",
"cd /wherever/your/files/are && source activate cvxpy_env && python example.py"
};
Or better yet, pack it all into a single shell script, and then just Runtime.exec("./my_script.sh") (don't forget to chmod +x it, though).
Try
String[] command = {
"/bin/bash",
"-c",
"source activate abc_env; " + "python example.py"
};

Unable to execute Unix command through Java code

case "BVT Tool":
System.out.println("Inside BVT Tool");
try {
String[] command1 = new String[] {"mv $FileName /bgw/feeds/ibs/incoming/"};
Runtime.getRuntime().exec(command1);
} catch(IOException e) {
System.out.println("execption is :"+ e);
e.printStackTrace();
}
break;
I'm unable to execute the Unix command. It's showing the following exception:
java.io.IOException: Cannot run program mv $FileName /bgw/feeds/ibs/incoming/":
CreateProcess error=2, The system cannot find the file specified.
I agree with #Reimeus on most points, but I want to point out that there reason you're getting this particular error message is a crosscontamination between 2 of the overloaded versions of exec:
String command1 = "mv $FileName /bgw/feeds/ibs/incoming/";
Runtime.getRuntime().exec(command1);
Would work - it's allowed to specify the command and its parameters in one String if you use the overloaded version that expects a String
String[] command1 = new String[] {"mv", "$FileName", "/bgw/feeds/ibs/incoming/"};
Runtime.getRuntime().exec(command1);
would work too, because it uses the the exec version expecting a String array. That version expects the command and its parameters in separate Strings
Please note that I here assume that $Filename is actually the name of the file, so no shell-based substitution will take place.
EDIT: if FileName is a variable name as you seem to suggest elsewhere in the comments, try
String[] command1 = new String[] {"mv", FileName, "/bgw/feeds/ibs/incoming/"};
But : with Commons IO you could just do
FileUtils.moveFileToDirectory(new File(FileName), new File("/bgw/feeds/ibs/incoming/") , true);
JavaDoc
which is
totally portable between Mac, Windows and Linux (your version won't work on Windows)
is faster because it doesn't need to spawn an external process
gives you more information when something goes wrong.
First, you should probably be using ProcessBuilder. The command you have is "mv" the rest should be arguments,
// I'm not sure about $FileName, that's probably meant to be a shell replace
// and here there is no shell.
ProcessBuilder pb = new ProcessBuilder("mv",
System.getenv("FileName"), "/bgw/feeds/ibs/incoming/");
Apart from the fact that Runtime.exec is a very antiquated approach for running a command,
The complete String is being interpreted as the executable command. You need to use individual tokens in the String array. In addition you need to
use a shell to interpret the $FileName variable
String[] command1 = {"bash", "-c", "mv", "$FileName", "/bgw/feeds/ibs/incoming/"};

"Cannot run program" when using Runtime.exec with spaces in program filename

I am using the below code to open the "sample.html' file.
String filename = "C:/sample.html";
String browser = "C:/Program Files (x86)/Google/Chrome/Application/chrome.exe";
Runtime rTime = Runtime.getRuntime();
Process pc = rTime.exec(browser + filename);
pc.waitFor();
However, I am getting the below error.
java.io.IOException: Cannot run program "C:/Program": CreateProcess error=2, The system cannot find the file specified
Could someone please help me figure this. Thanks in advance.
Runtime.exec(String) automatically splits the string at spaces, assuming the first token is the command name and the rest are command line parameters. Also you do not have a space between browser and file, although that is not the root cause of the problem.
It thinks you want to run "C:/Program" with two command line arguments:
"Files"
"(x86)/google/Chrome/Application/chrome.exeC:/sample.html"
Use Runtime.exec(String[]) instead, that way you have full control over what is what:
String[] command = new String[]{browser, filename};
Runtime.exec(command);
Try this.
String filename = "C:\\sample.html";
String browser = "C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe";
Runtime runtime = Runtime.getRuntime();
try {
runtime.exec(new String[] {browser, filename});
} catch (IOException e) {
e.printStackTrace();
}
Stop using Runtime.exec(String) - the problem is in how it processes the single string input.
The error message indicates how/where it is failing: note that it stops after "C:/Program" (or, the first space). This indicates that exec parsed the string "incorrectly" and thus isn't even looking for the correct executable.
Cannot run program "C:/Program"
Instead, consider the use of ProcessBuilder. While the usage is still system-dependent, ProcessBuilder allows separation of the executable file-name (and need to deal with it specially) and the arguments and does it's darnedest to invoke the target correctly.
String filename = "C:\\sample.html";
String browser = "C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe";
ProcessBuilder pb = new ProcessBuilder(browser, filename);
// setup other options ..
// .. and run
Process p = pb.start();
p.waitFor();
From what I can tell, in Windows, ProcessBuilder will wraps the individual components in quotes; this can create a different problem when arguments contain quotes..
Parameters must be passed separately:
Process pc = rTime.exec(new String[]{browser, filename});
Using exec() is not like using the command line - you can not use spaces to delimit the command from its parameters. Your attempt would try to execute a command whose path was the concatenation of the exec and the filename as one giant string.

Categories