Java ProcessBuilder: space within quotation marks - java

I am using ProcessBuilder to run FFMPEG to convert and label some of my MP3-Files.
Manually using the following in a .bat file works as expected:
"E:\Dokumente\workspace\MusicBot\ffmpeg\bin\ffmpeg.exe"
-i "The Glitch Mob - We Can Make The World Stop.mp4"
-metadata author="The Glitch Mob"
-metadata title="We Can Make The World Stop"
-ab 320k "mob.mp3"
Now what i am trying to achieve using java's ProcessBuilder
ProcessBuilder pr = new ProcessBuilder(FFMPEG_PATH,
"-i", target.getAbsolutePath(),
"-metadata", "title=\"We Can Make The World Stop\"",
"-metadata", "author=\"The Glitch Mob\"",
"-ab", "320k",
tar.getAbsolutePath());
results in a [NULL # 000000000032f680] Unable to find a suitable output format for 'Can'.
Using title and author without spaces in them works, however.

The double quotes on the command line are there to tell the shell interpreter not to split your string into multiple parameters. This is to ensure that the application receives title=We Can Make The World Stop as a single argument.
Since ProcessBuilder handles multiple command line arguments explicitly, there's no need for escaping whitespace when calling it.

Related

Java ProcessBuilder redirectInput with cat

I am writing a Java application that needs to execute the unix cat command using ProcessBuilder. I know I can use the arguments to the ProcessBuilder object to specify the file for cat to use. However, to standardize the interface, how would I use redirectInput() instead to pass the input file?
I'm assuming this would work as I can perform cat < foo.txt in the command line, which is equivalent to redirectInput() in ProcessBuilder (right?)
Help is much appreciated :)
Why not just try it?
I've written a simple test code:
new ProcessBuilder("cat")
.redirectInput(new File("/tmp/test", "i.txt"))
.redirectOutput(new File("/tmp/test", "o.txt"))
.start()
.waitFor();
And it successfully copied some text from i.txt to o.txt.

Python 2.7 subprocess call method not working to run java command

I am trying to use a python script to manipulate the input files for my java program. The way I am doing it is I am generating the file name and passing it to subprocess.call() method to execute. Here is my program:
def execJava(self):
self.thisCmd="pause"
call(self.javaCmd,shell=True)
call(self.pauseCmd,shell=True)
Where,
self.javaCmd = 'java -ea -esa -Xfuture -Xss64m -classpath "C:\FVSDK_9_1_1\lib\x86_64\msc_12.0-sse2_crtdll\*" -Djava.library.path="C:\FVSDK_9_1_1\lib\x86_64\msc_12.0-sse2_crtdll;C:\FVSDK_9_1_1\lib\x86_64\share" com.cognitec.jfrsdk.examples.MatchFIRAgainstGallery C:\FVSDK_9_1_1\etc\frsdk.cfg 0 .\tmp\frsdk-scratch\probe_1.fir .\tmp\test\*'
Yes, it's a long complex java instruction but when I run it in the command prompt it works fine. Only when I pass it as a string it doesn't run and returns:
Exception in thread "main" java.lang.Error
After some exploration into the problem, I have discovered that it is due to \x, \t in the instruction, so it is executing
.\tmp\test\*
as
mp est\*
as it replaces \t with tab space while executing. I have looked up quite a bit and didn't find any solution. Any help is much appreciated.
Use forward slashes "/" instead of back slashes "\" for your paths.

Execute bash script and pass arguments with spaces from java

I know there are a lot of post about executing commands from Java but I just can't get this to work. Here is what I'm trying to do, I have a bash script, it receives 2 arguments which might or might not have spaces, then from Java I'm executing the script and passing the arguments like this(I'm surrounding the arguments with quotes and escaping them with backslashes):
String cmd = "/opt/myScript \"/opt/myPath1\" \"/opt/myPath2 with spaces\"";
Runtime rt = Runtime.getRuntime();
rt.exec(cmd);
I also tried to use the ProcessBuilder class like this:
String myScript = "/opt/myScript";
String myArg1= "/opt/myPath1";
String myArg2 = "/opt/myPath2 with spaces";
ProcessBuilder pb = new ProcessBuilder(myScript , myArg1, myArg2);
pb.start;
Arguments with no spaces are received successfully but I still have problems with the second one.
I thought the ProcessBuilder class would handle the spaces but seems like I'm missing something.
I'm not sure if it has something to do, but just in case here is my script:
#!/bin/bash
PATH=$PATH:$1
gnome-terminal --working-directory $2
$1 and $2 are the arguments sent from Java.
Get the same trouble, finally solved with:
Runtime.getRuntime().exec(new String[]{"bash", "-c", <command with spaces>});
Runtime.exec() is an overloaded method. There are several possible ways how to call it. The call exec(String command) executes the specified string command but the argument are separated by spaces here. The method exec(String[] cmdarray) executes the specified command and arguments. There are other exec() variants but the best for you is
String cmd[] = new String[] {"/opt/myScript", "/opt/myPath1", "/opt/myPath2 with spaces" };
Runtime rt = Runtime.getRuntime();
rt.exec(cmd);
It is possible to use ProcessBuilder can be used as well for argument passing. I think the only error is missing parenthesis after pb.start.
And last but not least the script has a major bug. It does not contain quutes arround $2. It should be
#!/bin/bash
PATH="$PATH:$1"
gnome-terminal --working-directory "$2"

Passing pre-escaped command-line arguments to ProcessBuilder

I bumped into this problem today when setting up a local set of communicating programs. Basically one of my applications is sending some data to another, and part of this data is a string containing a command to execute (like you would from the command-line). Let's say, for example:
g++ foo.cc bar.cc -o foobar
is the command sent by my first application. The second application, which receives the command (amongst other things), needs to execute this command after doing some other processing.
Now, at first I thought this would be trivial using a ProcessBuilder:
String exampleCommand = "g++ foo.cc bar.cc -o foobar";
ProcessBuilder builder = new ProcessBuilder(exampleCommand);
builder.start().waitFor();
However this is where the problem occurs.
CreateProcess error=2, The system cannot find the file specified
Okay, no worries I guess I can't just dump the whole thing into the builder. The first part of the command is usually a trivial string so I thought I could probably get away with a split around the first ' ' to separate the program name and arguments.
String exampleCommand = "g++ foo.cc bar.cc -o foobar";
String[] parts = exampleCommand.split(" ", 2);
ProcessBuilder builder = new ProcessBuilder(parts[0], parts[1]);
builder.start().waitFor();
And this brought me a little closer, the g++ file could now be found correctly, however after examining the stderr of g++ I found that the following error had occurred:
g++.exe: error: foo.cc bar.cc -o foobar: No such file or directory
At this point I realised that the ProcessBuilder class must be escaping all arguments passed to it in preparation for the command-line (hence the reason it usually takes arguments as an array of individual arguments rather than just a predefined argument string).
My question is, "Is there any way to pass a raw string of arguments to a ProcessBuilder and say THERE, execute EXACTLY this?"
Because the command comes from another application and is in no way static I can't just break the arguments down into an array beforehand and pass them to the ProcessBuilder constructor properly. The arguments are not so trivial that simply splitting the string around a ' ' will work properly either; arguments might contain spaces escaped with double quotes. For example:
g++ "..\my documents\foo.cpp" bar.cpp -o foobar
Could be a command coming from the application and splitting that string around ' ' and passing it to the ProcessBuilder will result in corrupt arguments.
If there is no proper way to do this can someone please point me to a standalone command line argument parser (in Java) that can turn a command-line string into a valid String[]?
Okay I feel rather foolish now but I achieved my desired result by simply reverting back to the good old Runtime.getRuntime().exec(...). I'll leave the question up in case anyone is as silly as me and find it useful.
String exampleCommand = "g++ foo.cc bar.cc -o foobar";
Runtime sys = Runtime.getRuntime();
sys.exec(exampleCommand);
Easy.
A comment to the Runtime.getRuntime().exec(...) solution:
The Runtime.getRuntime().exec(...) is not good anymore. In java executed on OSX El Capitan, 'Runtime.getRuntime().exec(...)' contains an error that sometimes closes the opened process when the java program exits. It works fine on previous OSX versions. However, ProcessBuilder works on all OSX versions.
(Haven't posted enough to have a enough rep points to make this as a normal comment.)

error while running CRF++ from a java project

I want to call CRF++ toolkit from a java program. I type the following:
Process process = runtime.exec("/home/toshiba/Bureau/CRF++-0.54/.libs/lt-crf_learn /home/toshiba/Bureau/CRF++-0.54/example/atb/template /home/toshiba/Bureau/CRF++-0.54/example/atb/tr_java.data");
process.waitFor();
But, I have the the following error:
CRF++: Yet Another CRF Tool Kit
Copyright (C) 2005-2009 Taku Kudo, All rights reserved.
Usage: /home/toshiba/Bureau/CRF++-0.54/.libs/lt-crf_learn [options] files
-f, --freq=INT use features that occuer no less than INT(default 1)
-m, --maxiter=INT set INT for max iterations in LBFGS routine(default 10k)
-c, --cost=FLOAT set FLOAT for cost parameter(default 1.0)
-e, --eta=FLOAT set FLOAT for termination criterion(default 0.0001)
-C, --convert convert text model to binary model
-t, --textmodel build also text model file for debugging
-a, --algorithm=(CRF|MIRA) select training algorithm
-p, --thread=INT number of threads(default 1)
-H, --shrinking-size=INT set INT for number of iterations variable needs to be optimal before considered for shrinking. (default 20)
-v, --version show the version and exit
-h, --help show this help and exit
I 'm wondering if any one could help me?
I don't think that's a bug in CRF++, since you are able to run it from command line. So the actual question is how to pass arguments properly when starting a process using Runtime.exec(). I would suggest trying the following:
String[] cmd = {"/home/toshiba/Bureau/CRF++-0.54/.libs/lt-crf_learn",
"/home/toshiba/Bureau/CRF++-0.54/example/atb/template",
"/home/toshiba/Bureau/CRF++-0.54/example/atb/tr_java.data"};
Process p = Runtime.getRuntime().exec(cmd);
This may help since Runtime.exec() sometimes splits the command line into arguments in a rather strange fashion.
Another potential problem is mentioned here: Java Runtime.exec()
There's a simple solution for this. Just write your command into a temporary file and execute that file as Runtime.getRuntime.exec("sh <temp-filename>"). Later you can delete this file. I will explain reason behind this if this solution works for you.

Categories