I'm looking into a most efficient way to decide:
It is known that to start a shell script from Java one should start the shell instead:
ProcessBuilder pb = new ProcessBuilder("/bin/sh", "script.sh", "arg1", "arg2);
To start a binary one should start the binary itself:
ProcessBuilder pb = new ProcessBuilder("/path/binary", "arg1", "arg2);
If a binary is executed with shell, it produces an error:
ProcessBuilder pb = new ProcessBuilder("/bin/sh", "/path/binary", "arg1", "arg2);
(sh: cannot execute binary file)
If a shell script is executed without the shell binary, it produces an error:
ProcessBuilder pb = new ProcessBuilder("script.sh", "arg1", "arg2);
(error 2: file not found)
I'm in a situation where my application doesn't know what it starts, binary or a script.
The started application is a event handler provided by the end user. It most likely be a shell script executed under Unix; but it can be a *.cmd under Windows, or a Perl script executed under some obscure platform. It is Java, after all.
My first naive attempt was to start the command line with the shell, and see if it works. If not, try to execute it as a binary.
This is ugly and risky: under some unknown combination of platform and shell the second ran may still execute the script, second time, with unpredictable results.
Also, I cannot tell when the script started OK and failed due to some issue of its own from when I just cannot start it.
The best thing I'm considering now is:
Please advise if you have any better ideas in mind.
UPDATE/PARTIAL SOLUTION
Thanks to everyone who shared their thoughts with me.
Turns out, I have confused myself and the rest of the Internet :)
It is not required to prepend the shall binary before the user-entered command line providing that:
While I was testing my code, one or another of these conditions did not met. :-(
After performing the test carefully from the scratch script has been executed.
Point 3 is only can be done by the user, and have to be documented in User Manual.
Due to the way these scripts are propagated to the target system, they may be not executable and may not be in PATH.
The only path I care about is relative one, so it is enough to prepend a ./ to any relative path.
Making the scripts executable under Unix (and any other platform) is a more of a challenge. It is not WORA. Placing /bin/sh in front of it may help, but if I remember right under Solaris the shell will not execute a non-executable script.
I'll post another update later this week.
It should be a red flag that you have to jump through these hoops just to run a command. First because this is getting really complicated, and second because Java was designed to be platform independent. When you are investigating OS-specific hacks to make built-in classes work you should step back and re-examine your assumptions.
ProcessBuilder pb = new ProcessBuilder("script.sh", "arg1", "arg2);
(error 2: file not found)
Notice that the error message is "file not found", not "cannot execute shell script" or some such error. The most likely cause for this error is not that you're executing a script, but that the script can't be found.
If the script is in the current directory then you need to add a ./
in front. If you don't put an explicit path to the executable then the executable must reside in one of the directories in your $PATH
environment variable. The current directory .
is usually not included in $PATH
by default.
ProcessBuilder pb = new ProcessBuilder("./script.sh", "arg1", "arg2);
If the script name is a user-supplied value then I would levy this requirement on the user--you could add the ./
for them, but UNIX programs generally try to avoid being too helpful. If they forget to put ./
then that's their problem!
One possible solution is to generate a script that wraps the executing script/binary from within your program. That way you know it's always a script. The generated script simply executes the inner script/binary and returns the error code (and possibly redirects input/output). When finished, you can simply delete it. Java allows you to create temporary files very easily.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With