Unable to execute a command if it contains spaces using java - java

Issue:- If the executable command contain's any spaces then System.exec is omitting the string content after the first space.
For example:- if command="/opt/GUIInstaller/installers/abc def gh.bin"
Then java is executing command up-to /opt/GUIInstaller/installers/abc only and resulting a error like java.io.IOException: "/opt/GUIInstaller/installers/abc": error=2, No such file or directory
protected void launch(final String command)
{
try
{
if(command.contains("null"))
{
logger.error("Installer is not located in the specified folder: "+command);
System.exit(0);
}
runTime.exec(command);
}
catch (IOException ioException) {
logger.error(ioException.getMessage(), ioException);
}
}
Is I am doing any mistake, please help me to solve this issue.
Environment:- Java7 update9 + RHEL6

As described in the javadocs of Process#exec(), exec(String) simply splits the given command string into tokens via StringTokenizer. If you do that job jourself by passing tokens to exec(), spaces in there are no problem:
runTime.exec(new String[] {"/opt/GUIInstaller/installers/abc def gh.bin", "--param1=foo"});

Add
if(command.contains(" ")){command.replace(" ","\\ ");}
before the runTime.exec(command);
This basically just replaces spaces with escaped spaces..
Edit:
Or to make it smoother try to execute this
runTime.exec(command.replace(" ","\\ "));
without adding the aforementioned line..

Related

Path with spaces

I am not a programmer and I need to fix some code to solve a problem.
The problem is that the app does not read file paths with spaces.
Code:
private void jMenuHELPActionPerformed(java.awt.event.ActionEvent evt) { //GEN FIRST:event_jMenuHELPActionPerformed
try {
Runtime.getRuntime().exec("cmd /c start "+" C:\Users\rafi\Documents\Name with spaces\file.txt");
} catch (IOException ex) {
ex.printStackTrace();
}
// ...
}
When I try to open a file from within the app, it opens a window with the following error:
Windows cannot `find C:\Users\rafi\Documents\Name`. Make sure that the name is correct.
It reads the path only to the first space.
How can I solve this problem?
Try putting the path in quotes. On the command line different parameters are separated by whitespace, and thus the path needs to be surrounded by quotes to indicate it is a single parameter.
Runtime.getRuntime().exec("cmd /c start \"C:\\Users\\rafi\\Documents\\Name with spaces\\file.txt\"");
Use the exec method that takes an array of arguments instead. Don't forget you also need to escape your backslashes.
Runtime.getRuntime().exec(new String[] {"cmd", "/c", "start", "C:\\Users\\rafi\\Documents\\Name with spaces\\file.txt"});
You need to escape the \ characters and Desktop.open(File) is how I would use the operating system to open a given file with its' default application for that file type.
File file = new File("C:\\Users\\rafi\\Documents\\Name with spaces\\file.txt");
try {
Desktop.getDesktop().open(file);
} catch (IOException e) {
e.printStackTrace();
}
Have you tried doing:
private void jMenuHELPActionPerformed(java.awt.event.ActionEvent evt) {//GEN FIRST:event_jMenuHELPActionPerformed
try {
Runtime.getRuntime().exec("cmd /c start "+" C:\Users\rafi\Documents\Name\ with\ spaces\file.txt");
} catch (IOException ex) {
ex.printStackTrace();
}
}
That should escape the space character, instead of putting with and spaces\file.txt as arguments.
You update your code folowing below:
private void jMenuHELPActionPerformed(java.awt.event.ActionEvent evt) { //GEN FIRST:event_jMenuHELPActionPerformed
try {
Runtime.getRuntime().exec("cmd /c start "+" C:\\Users\\rafi\\Documents\\Name with spaces\\file.txt");
} catch (IOException ex) {
ex.printStackTrace();
}
// ...
}

java.lang.Runtime exception "Cannot run program"

I am getting an exception like java.io.IOException: Cannot run program cat /home/talha/* | grep -c TEXT_TO_SEARCH": error=2, No such file or directory while executing the command below despite that there are no issues when I execute the same command through the terminal. I need to execute and return the output of the command below:
cat /home/talha/* | grep -c TEXT_TO_SEARCH
Here is the method used to execute commands using Runtime class:
public static String executeCommand(String command) {
StringBuffer output = new StringBuffer();
Process p;
try {
p = Runtime.getRuntime().exec(command);
p.waitFor();
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = "";
while ((line = reader.readLine()) != null) {
output.append(line + "\n");
}
} catch (Exception e) {
e.printStackTrace();
}
return output.toString();
}
Runtime.exec does not use a shell (like, say, /bin/bash); it passes the command directly to the operating system. This means wildcards like * and pipes (|) will not be understood, since cat (like all Unix commands) does not do any parsing of those characters. You need to use something like
p = new ProcessBuilder("bash", "-c", command).start();
or, if for some bizarre reason you need to stick to using the obsolete Runtime.exec methods:
p = Runtime.getRuntime().exec(new String[] { "bash", "-c", command });
If you are only running that cat/grep command, you should consider abandoning the use of an external process, since Java code can easily traverse a directory, read lines from each file, and match them against a regular expression:
Pattern pattern = Pattern.compile("TEXT_TO_SEARCH");
Charset charset = Charset.defaultCharset();
long count = 0;
try (DirectoryStream<Path> dir =
Files.newDirectoryStream(Paths.get("/home/talha"))) {
for (Path file : dir) {
count += Files.lines(file, charset).filter(pattern.asPredicate()).count();
}
}
Update: To recursively read all files in a tree, use Files.walk:
try (Stream<Path> tree =
Files.walk(Paths.get("/home/talha")).filter(Files::isReadable)) {
Iterator<Path> i = tree.iterator();
while (i.hasNext()) {
Path file = i.next();
try (Stream<String> lines = Files.lines(file, charset)) {
count += lines.filter(pattern.asPredicate()).count();
}
};
}
$PATH is an environment variable that tells the system where to search for executable programs (it's a list of directories separated by colons). It is usually set in your .bashrc or .cshrc file but this is only loaded when you log in. When Java runs, $PATH is likely not set because the rc file is not executed automatically, so the system can't find programs without specifying exactly where they are. Try using /bin/cat or /usr/bin/cat instead of just cat and see if it works. If it does, $PATH is your problem. You can add $PATH=/bin:/usr/bin to your script or just leave it with the directory name specified (e.g. /bin/cat).
Just because you can execute it in a login session doesn't mean it will work the same when a daemon like your Java program runs. You have to know what's in your .bashrc or .cshrc file and even sometimes how the system file is written (/etc/bashrc) in order to know how to write a script that runs under a daemon. Another consideration is that daemons often run under the context of a different user, and that throws things off, too.

Java: Convert command array to string that can execute in bash

I have a command in array format that I can pass to execve(). For example, the command is:
echo "It's Nice"
and the array I have is ["echo","It's Nice"]. I'm trying to convert this array into a string that I can write in bash and execute properly. I obviously cannot join on this array with space delimiter because I will get: echo It's Nice which cannot be run since it has an unterminated single quote.
Is there a BKM to convert this to a runnable string? maybe a library that does that already in Java? It can get tricky when the command has many special characters that should be escaped\quoted in order to run properly.
EDIT:
I would like to make my question clearer. The user gives me his command as a string array, I execute it and everything works fine. Now I need to report to the user what I have ran. I do not want to show the command as an array, instead I would like to show it as a string that the user can simply copy and paste to his bash shell and execute it if he wants to. So my input is [echo, It's Nice] and my output should be echo "It's Nice". It seems like a simple function to write, but i'm not sure i'm thinking of all the end-cases here (like if the string has a quote or some other special character the shell manipulates). I was wondering maybe there's some code that already does that and covers the end cases i'm yet to think about.
You don't need to convert array to string, you can directly execute a command using ProcessBuilder:
String runShell(final String[] commandArgs) {
try {
final ProcessBuilder processBuilder = new ProcessBuilder(commandArgs);
processBuilder.redirectErrorStream(true); // merge stderr with stdout
Process process = processBuilder.start();
ret = process.waitFor();
BufferedReader br = new BufferedReader(new InputStreamReader(
process.getInputStream() ));
br.lines().forEach(System.out::println); // print stdout + stderr
process.destroy();
br.close();
}
catch (IOException|InterruptedException e) {
e.printStackTrace();
}
return commandArgs[0] + Arrays.asList(commandArgs).stream()
.skip(1)
.collect(Collectors.joining("\" \"", " \"", "\""));
}
and call it as:
runShell(new String[] {"pwd"}); // print current working directory
runShell(new String[] {"ls", "-l"}); // list all the files and directories
runShell(new String[] {"echo", "It's Nice"}); // echo something
That's easy to do in Java 8:
String joined = String.join(" ", iteratable);

Runtime.exec on argument containing multiple spaces

How can I make the following run?
public class ExecTest {
public static void main(String[] args) {
try {
//Notice the multiple spaces in the argument
String[] cmd = {"explorer.exe", "/select,\"C:\\New Folder\\file.txt\""};
//btw this works
//String cmd = "explorer.exe /select,\"C:\\New Folder\\file.txt\"";
//and surprisingly this doesn't work
//String[] cmd = {"explorer.exe", "/select,\"C:\\New Folder\\file.txt\""};
//Update: and (as crazy as it seems) the following also worked
//String[] cmd = {"explorer.exe", "/select,\"C:\\New", "Folder\\file.txt\""};
Runtime.getRuntime().exec(cmd);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Using Java 6. Tested under Vista x64. By the way, taking the string that gets executed (you'll have to use the String version of exec to get it) and using it in the Search field of Vista's start menu will run as expected.
Ok, this is not simply an update but also an answer so I'm filing it as one. According to all information I could find, the following should theoretically do it:
String[] cmd = {"explorer.exe", "/select,\"C:\New", "", "", "", "", "", "", "Folder\file.txt\""};
The multiple spaces have been broken into empty strings and the array version of exec is used.
Using the above array, I debugged the loop in lines 50-75 of java.lang.ProcessImpl where a string is finally constructed. The resulting string was:
explorer.exe /select,"C:\New Folder\file.txt"
This is what is passed as the 1st argument to ProcessImpl's native create method (line 118 same class), which as it seems fails to run properly this command.
So I guess it all ends here... sadly.
Thnx prunge for pointing out the java bug.
Thnx everyone for their time and interest!
A miracle, it works!
Don't ask me why, but when i, after quite a while of nerve-wrecking research in the internets, was close to give up and use a temporary batch file as a workaround, i forgot to add the /select, parameter to the command, and, who would have thought, the following works on my Win 7 32Bit System.
String param = "\"C:\\Users\\ME\\AppData\\Local\\Microsoft\\Windows\\Temporary Internet Files\\\"";
try {
String[]commands = new String[]{"explorer.exe", param};
Process child = Runtime.getRuntime().exec(commands);
} catch (IOException e1) {
System.out.println("...");
}
General Solution:
The solution of the bug-database mentioned by prunge in his post (http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6511002) worked fine for me.
Reason:
Apparently the problem lies with the commenting of some characters done by java which it does before actually executing the command string.
You have to do the commenting yourself by tokenizing your command string, to prevent the faulty java one to spring into action and mess everything up.
How to fix:
So, in my case i had to do the following (tokenizing my command string, so that no spaces are left inside the string):
String param[] = {
"explorer.exe",
"/select,C:\\Users\\ME\\AppData\\Local\\Microsoft\\Windows\\Temporary",
"Internet",
"Files\\"};
try {
Process child = Runtime.getRuntime().exec(param);
} catch (IOException e1) {
System.out.println("...");
}
As you can see i basically started a new String wherever a space occured, so "Temporary Internet Files" became "Temporary","Internet","Files".
Always use Runtime.exec(String[]), not Runtime.exec(String) unless the command line is extremely simple.
Use new File(pathName).canExecute() first to check whether it's executable or not
EDIT:
public static void runAll(String... cmd)
{
for(String s : cmd)
{
try
{
Runtime.getRuntime().exec(cmd);
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
and then you can use it like: runAll("explorer.exe", "taskmgr.exe");
The characters ,-& and double spaces, all combined are a nightmare!
All the answers exposed here failed for "\\NAS\media\Music\Artistes\E\Earth, Wind & Fire\1992 - The eternal dance - Vol. 1 (1971-1975) (double space between 'Vol. 1' and '(1971').
I have no other choice than writing a temporary batch file:
void openFolderOf( Album album ) {
try {
final String path = album._playList.getParent();
final File batch = File.createTempFile( getClass().getSimpleName(), ".bat" );
try( PrintStream ps = new PrintStream( batch )) {
ps.println( "explorer.exe \"" + path + '"' );
}
Runtime.getRuntime().exec( batch.getAbsolutePath());
}
catch( final Throwable t ) {
t.printStackTrace();
}
}
Note: on cmd.exe, the line explorer "\\NAS..." works well but not with Runtime.exec() nor ProcessBuilder.
Could be a Java bug. See:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6511002
Did a bit of debugging out of curiosity, I think things are becoming unstuck in java.lang.ProcessImpl (see the constructor). Noticed that when it got to actually calling the underlying Windows API the string had turned into
explorer.exe "/select,"c:\New Folder\test.txt""
So that might explain why, as for workarounds see the bug database link.
For your specific case of needing the reveal/select command, I get around the windows quote nightmare by using cmd /c start:
String[] cmd = {"cmd", "/c", "start explorer.exe /select," + path};
Where path is the absolute path from a File object.
A better way to do it would be using ProcessBuilder object:
Process p;
p = new ProcessBuilder("/Applications/Sublime Text.app/Contents/MacOS/sublime_text", homeDir + _CURL_POST_PUT_CMDS).start();
int exitValue = p.waitFor();
if (exitValue != 0){
System.out.println("Error to open " + homeDir + _CURL_POST_PUT_CMDS);
}
Simple way to resolve this problem for files is java.awt.Desktop Since 1.6
Example:
Desktop.getDesktop().open(new File(fullFileName));

Better way of opening a Document from Java?

I've been using the following code to open Office Documents, PDF, etc. on my windows machines using Java and it's working fine, except for some reason when a filename has embedded it within it multiple contiguous spaces like "File[SPACE][SPACE]Test.doc".
How can I make this work? I'm not averse to canning the whole piece of code... but I'd rather not replace it with a third party library that calls JNI.
public static void openDocument(String path) throws IOException {
// Make forward slashes backslashes (for windows)
// Double quote any path segments with spaces in them
path = path.replace("/", "\\").replaceAll(
"\\\\([^\\\\\\\\\"]* [^\\\\\\\\\"]*)", "\\\\\\\"$1\"");
String command = "C:\\Windows\\System32\\cmd.exe /c start " + path + "";
Runtime.getRuntime().exec(command);
}
EDIT: When I run it with the errant file windows complains about finding the file. But... when I run the command line directly from the command line it runs just fine.
If you are using Java 6 you can just use the open method of java.awt.Desktop to launch the file using the default application for the current platform.
Not sure if this will help you much... I use java 1.5+'s ProcessBuilder to launch external shell scripts in a java program. Basically I do the following: ( although this may not apply because you don't want to capture the commands output; you actually wanna fire up the document - but, maybe this will spark something that you can use )
List<String> command = new ArrayList<String>();
command.add(someExecutable);
command.add(someArguemnt0);
command.add(someArgument1);
command.add(someArgument2);
ProcessBuilder builder = new ProcessBuilder(command);
try {
final Process process = builder.start();
...
} catch (IOException ioe) {}
The issue may be the "start" command you are using, rather than your file name parsing. For example, this seems to work well on my WinXP machine (using JDK 1.5)
import java.io.IOException;
import java.io.File;
public class test {
public static void openDocument(String path) throws IOException {
path = "\"" + path + "\"";
File f = new File( path );
String command = "C:\\Windows\\System32\\cmd.exe /c " + f.getPath() + "";
Runtime.getRuntime().exec(command);
}
public static void main( String[] argv ) {
test thisApp = new test();
try {
thisApp.openDocument( "c:\\so\\My Doc.doc");
}
catch( IOException e ) {
e.printStackTrace();
}
}
}

Categories