Pass shell script argument containing spaces as java system property - java

Have a shell script which, in turn, run a java program.
The script is invoked as follows :
./script.sh 1 2 3 4 "ab cd"
The 5th shell argument (ab cd) must be passed as a a java system property, what I'm doing is this :
JAVA_OPTS="-Xmx512M -Dlog4j.defaultInitOverride=true"
if [ "$5" ] ; then
JAVA_OPTS="$JAVA_OPTS -Dconfig.path=$5"
fi
Then, run java (JAVA_EXE & CP have proper values) :
$JAVA_EXE $JAVA_OPTS -classpath $CP com.foo.Main
Receiving this error :
Error: Could not find or load main class cd
If passing "abcd" instead of "ab cd" everything is ok.
If passing inline, just surround the value with quotes :
java -Xmx512M -Dconfig.path="ab cd" com.foo.Main
The problem occurs when a variable must be used.
How should I pass the argument containing spaces correctly ?

Instead of building JAVA_OPTS as a string, you can build it as an array:
JAVA_OPTS=(-Xmx512M -Dlog4j.defaultInitOverride=true)
if [ "$5" ] ; then
JAVA_OPTS+=("-Dconfig.path=$5")
fi
"$JAVA_EXE" "${JAVA_OPTS[#]}" -classpath "$CP" com.foo.Main
(Note: the Bourne shell did not have arrays, and POSIX does not require shells to support them, so this approach is not maximally portable. If you use this approach, make sure the first line of your script is something like #!/bin/bash or #!/bin/zsh and not something like #!/bin/sh.)

The only solution I found is to use a special variable for the problematic param
CONFIG_PATH="-Da=a"
if [ "$5" ] ; then
CONFIG_PATH=-Dconfig.path=$5
fi
$JAVA_EXE $JAVA_OPTS "$CONFIG_PATH" -classpath $CP com.foo.Main
It must have some value, otherwise the empty value will be taken as the name of the main class.

$JAVA_EXE $JAVA_OPTS -classpath $CP com.foo.Main MUST be $JAVA_EXE "$JAVA_OPTS" -classpath $CP com.foo.Main - Pay attention to the double quotes around $CP
EDIT: JAVA_OPTS="$JAVA_OPTS -Dconfig.path=$5" should also be JAVA_OPTS="$JAVA_OPTS -Dconfig.path='"'$5'"'"

Related

How can I redefine a property value in .sh file when starting a Java application

I have a script file app.sh:
java -DenabledFeature=true -jar filename [args]
When I launch the script:
./app.sh -DenabledFeature=false
Where in code
Boolean isFeatureEnabled = System.getProperty("enabledFeature", "true").equals("true")
the value is always true;
How can I change the value of the property to false?
if you always run your application by ./app.sh -DenabledFeature=false, you can directly pass the command line arguments as java arguments by this:
java $1 -jar filename [args]
here $1 will capture the sh first argument.
Update as you can pass several values as arguments, you can check if you have pass false value for enable feature like:
app.sh
#!/bin/bash
enabledFeature=true
if [[ "$*" =~ '-DenabledFeature=false']] ;
then
enabledFeature=false
#echo $enabledFeature
fi
java -DenabledFeature=$enabledFeature -jar filename [args]

apache.commons.cli and "long" command-line parameters in Java

Is it possible to use 'long' parameters for command-line options with apache.commons.cli.CommandLineParser in java? 'Long' I mean not a single word, but a sentence in block-quotes ('"'). Java application is being started from bash-script file.
Script file:
#!/bin/bash
java -cp <classpath> MyClass $#
Call (which returns only "long" for '-p' argument and "another" for '-r' argument):
./script.sh -p "long parameter" -r "another long parameter"
Now I can only do something like this to get "long parameter" string:
./script.sh -p "long" -p "parameter"
Of course I can add '-p' programmatically as many times as needed, but this prevents me from using '-' sign in parameter values, as I need to track other command-line switches. Besides this seems to be far not correct approach.
CommandLine options are created like this:
org.apache.commons.cli.Options options = new Options();
options.addOption(Option.builder("p").longOpt("param").hasArg().desc("parameter description").build());
And then parsed like this:
CommandLineParser parser = new DefaultParser();
CommandLine line = parser.parse( options, args );
if (line.hasOption('p')) params = line.getOptionValues("param");
Finally it's got clear (thanks to Jim Garrison) that the problem is caused by calling java class from bash-script (passing all the arguments with $#). Wrapping $# into double quotes in script solved the problem. Like this:
#!/bin/bash
java -cp <path> MyClass "$#"
instead of incorrect
#!/bin/bash
java -cp <path> MyClass $#

Launching Java With Java_OPTS

This should be a pretty simple question, I can't believe I wasn't able to find anything from googling.
I'm using powershell and I'm trying to run a java app from command line:
$memory = "-Xms128m -Xmx1028m -XX:MaxPermSize=512m"
$ssl = "-Djavax.rmi.ssl.client.enabledProtocols=`"TLSv1`" -Djavax.rmi.ssl.client.enabledCipherSuites=`"_removed_`" -Djavax.net.ssl.trustStorePassword=`"_removed_`" -Djavax.net.ssl.trustStore=`"_removed_`" -Djavax.net.ssl.keyStorePassword=`"_removed_`" -Djavax.net.ssl.keyStore=`"_removed_`" -Djava.endorsed.dirs=`"$($ddmsLoc)tomcat6\endorsed`""
$classpath = getClasspath "manager" $null
$java_opts = "$($memory) $($ssl) -Djavax.net.debug=all"
$cmd = "$($java) $($java_opts) -cp `"$($classpath)`" dss.vector.solutions.manager.server.ServerStatus -g"
Invoke-Expression $cmd
But for some reason it thinks my JAVA_OPTS parameters are the name of the java class I'm running:
Caused by: java.lang.ClassNotFoundException: .rmi.ssl.client.enabledProtocols=TLSv1
I have tried:
The ssl options with/without quotes around the value
Actually setting the JAVA_OPTS environment variable, until I read somewhere else that the JVM doesn't ever read that variable.
wrapping them in more quotes
I'm kind of at a loss here.
Etan Reisner posted a comment that helped me to solve it:
Why does PowerShell split arguments containing hyphens and periods?
Windows is (for some reason) splitting the parameters in half.
echo -Dmy.param=value
returns:
-Dmy
.param=value
If the parameter is wrapped in quotes, like:
echo "-Dmy.param=value"
Then it works just fine.

Losing java main args when using getopts in launch script

I have a script with 5 mandatory parameters (5 paths) and 3 options (-d for debug, -l for log4j override, -s for another override).
I'm managing it with getopts. The following script is simplified :
LOG4J_FILE=$DEFAULT_LOG4J_FILE
S_FILE=$DEFAULT_S_FILE
ECLIPSE_PROPS=
while getopts "l:s:d" flag; do
case "$flag" in
l) LOG4J_FILE="$OPTARG";;
s) S_FILE="$OPTARG";;
d) ECLIPSE_PROPS="-Xdebug ...";;
:) usage;;
?) usage;;
esac
done
shift $((OPTIND-1))
OPTIND=1
...
echo_and_eval $JAVA $ECLIPSE_PROPS -Dlog4.configuration=$LOG4J_FILE -Ds.file=$S_FILE -cp $CLASSPATH $MAIN_CLASS $ARGS
If I just put the 5 parameters, it works.
If I add one or two optional with parameters (l or s), it works.
If I add the -d option, I have no args in the Java main method.
Any clue ? This is driving me crazy.
It's OPTARG not OPTARGS -- http://www.gnu.org/software/bash/manual/bashref.html#index-getopts
l) LOG4J_FILE="$OPTARG";;
I would encourage you to get into the habit of quoting ALL your variables, that will protect any that contain whitespace or globbing chars:
java "$ECLIPSE_PROPS" -Dlog4.configuration="$LOG4J_FILE" -Ds.file="$S_FILE" -cp "$CLASSPATH" Main "$1" "$2" "$3" "$4" "$5"
Simply using echo to output the command line isn't going to show you how it gets parsed into individual arguments. foo 'bar baz' and foo bar baz are two very different commands, but they look the same when echoed.
Clearly, something in the actual value of the ECLIPSE_PROPS variable (that is, the argument to -d) is preventing the later arguments from being passed to the Java main method. If you supplied the actual code and actual values, we might be able to help you determine what that is.

Standard error not getting redirected from this java command in bash

I have the following shell script. For some reason the java program's standard error and standard output is not printed to the file "log" but instead always appear in the console. Is there a type some where or am I missing something?
JAVACMD="java -XX:+HeapDumpOnOutOfMemoryError -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=19000 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -Xss128k -Xmx700m -jar program.jar >log 2>&1 "
echo "Starting server...";
$JAVACMD&
Regrettably, you will have to use eval if you want to keep the redirection operators in the string value.
Like other shell-special characters, redirection operators are only evaluated if they are not quoted. When you expand the JAVACMD parameter it will split on whitespace, but it will not re-evaluate any special characters it includes. Using eval forces this re-evaluation.
The problem with eval is it forces every character be re-evaluated. In your case, none of the other characters will have any untoward affects. If your string value contained some other shell-special character (e.g. ;(){}…) that you did not want the shell to re-evaluate you would have to escape/quote it inside the string value so that eval would not give it a special meaning.
⋮
eval "$JAVACMD &"
To avoid problems with eval, I suggest moving the redirection out of the string value:
JAVACMD="… program.jar"
⋮
$JAVACMD >log 2>&1 &
Done this way the only characters in the string value that you need to watch out for are the whitespace characters (e.g. if you needed some embedded whitespace in one of the options/arguments; if you run into this you might consider using an array variable or "$#" (a singular, array-like variable available in all Bourne-like shells)).
Have you tried:
JAVACMD="java -XX:+HeapDumpOnOutOfMemoryError -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=19000 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -Xss128k -Xmx700m -jar program.jar"
echo "Starting server...";
$JAVACMD >log 2>&1 &
The redirections are considered as arguments to the java command as they are contained in the variable.
You can't actually stick redirections in a variable like that and expect bash to accept them. Simple example:
tesla:~ peter$ ECHOCMD='echo > log 2>&1'
tesla:~ peter$ $ECHOCMD
log 2>&1
I.e. your redirection indicators are becoming simple arguments, passed to your java invocation.
One workaround is to say eval $JAVACMD but it won't make your script any cleaner.

Categories