I've got an application written in Java that needs to call some utilities that are binary executables. It runs on anything that runs Java. What it needs to call is not a fixed set, but can be chosen by the user.
When I first wrote this back in the late 1990s, there was much spilled blood before I figured out that calling the utilities directly was extraordinarily problematic. The shortest comment is that some programs require a "context" and some don't, so generalized solutions are harder.
I wanted it to run the same everywhere like the Java paradigm claims, and while not wanting to start any kind of war I should point out that it just doesn't. I sure wish the Java folks would bother to resolve the major platform differences for us, but they have chosen not to and say that's just platform specific, not their problem. (Hey, if I'm just ignorant about "modern developments" with Java since, oh, 1.4, please tell me!)
For the curious, briefly, I had code like this:
if (ClientOS.indexOf("Windows") != -1) { if (ClientOS.equals("Windows 95")) { cmd = "command.com /C "; } else if (ClientOS.equals("Windows 98")) { cmd = "command.com /C "; //cmd = "cmd.exe /C "; } else if (ClientOS.equals("Windows NT")) { cmd = "cmd.exe /C "; } else if (ClientOS.equals("Windows 2000")) { cmd = "cmd.exe /C "; } else if (ClientOS.equals("Windows XP")) { cmd = "cmd.exe /C "; } else { cmd = "cmd.exe /C "; } } else {
So, for MANY years I've gotten by using Bash as a competent intermediary. I provided my app with a configurable "shell" variable which typically gets set on Linux to something like "/bin/bash"
. On Windows. to get some help, I've been using Cygwin, and a typical value there is "C:/cygwin/bin/bash -c"
, and I do away with the if-block seen above. Along the way I noticed that sometimes, on some versions, the -c
gets in the way, and in other cases, it's required. I have no idea why; until recently, either adding the -c or taking it away was enough.
Recently, however, I upgraded a whole bunch of machines, both Windows (and cygwin) and Linux, and then started noticing that not everything was working any more. SOME Programs continue to run just fine, but others don't. After an embarrassing number of hours, I've come to realize I don't understand enough about how things are SUPPOSED to work.
At the moment, it's all broken on the versions I have installed now, and I've had two problems;
It either can't find the executable at all, or;
The executable runs and can't find any of its required arguments - that I did pass.
This MAY fall into two categories: What's up with Java calling programs anyway!? And how POSIX BASH
is supposed to work. Because it's easy to do, I've down-graded Java a little with no improvements, so I'm more focused on the BASH
side at the moment. To be clear, calling Bash from an established Bash context always works "as per specficication", however, calling from Java does not! What I really need to do is figure out how to get it to always work from Java.
Every built-in I've tried runs no matter, however, for non-built-ins, I've learned you need to provide the full path to the program. Beyond that, I THOUGHT I knew you sometimes had to quote the entire command. Some versions of BASH seem to take the double quotes fine, others want single quotes.
When I first noticed trouble, before doing anything about it, I got errors where it gave the executable's full path followed by a colon then space, repeated twice, then:
"cannot execute binary file"
When it runs the executable I'm now getting a complaint from the program (unique to each executable) that it can't find its' arguments. On some attempts to fix this with either adding or dropping the -c or changing the quoting, I sometimes get:
executable_name: -c: line 0: unexpected EOF while looking for matching `'' executable_name: -c: line 1: syntax error: unexpected end of file
BTW, I found this StackOverflow article that discusses things, but it doesn't help.
I can tell you that when I practice that kind of launch of the executable - that is, quoting the executable to be called in single quotes and leaving the arguments dangling behind, the executable DOES run, but does NOT get any arguments.
Any input appreciated.
UPDATE FOR THE JAVA HEROS:
Don't be silly like the first commenter who just had to presume I wasn't using the Java built in functions. OF COURSE I use the Java built-in Runtime library. The particular call looks like this:
Process p = Runtime.getRuntime().exec(cmd);
Before you get your panties all in a twist, you need to figure out that Java DOES NOT create a solid, reliable process context that is often expected by running programs in various platforms. I wouldn't be telling you Java has issues launching programs if it wasn't true.