I'm trying to write a shell script which uses a command called jmxquery

This is what works on the command line:

[root@monitor jmxquery]# java -jar /opt/jmxquery/jmxquery.jar \
    -U service:jmx:rmi:///jndi/rmi://tomcat.cyberdyne.corp:1099/jmxrmi \
    -O java.lang:type=GarbageCollector,name='PS MarkSweep' \
    -A LastGcInfo \
    -K GcThreadCount

**JMX OK - LastGcInfo.GcThreadCount=4 | LastGcInfo.GcThreadCount=4**

As you can I see i get a JMX OK with thread count details. So I'm trying to do the same within a shell script. I have a variables defined like this:

attr_marksweep_threadcount="-O java.lang:type=GarbageCollector,name='PS MarkSweep' -A LastGcInfo -K GcThreadCount"

Then I run:

java -jar ${JAR} -U ${SERVICE_URL} $attr_marksweep_threadcount

Here is a snippet of what the output looks like with bash -x

+ attr_marksweep_threadcount='-O java.lang:type=GarbageCollector,name='\''PS MarkSweep'\'' -A LastGcInfo -K GcThreadCount'
+ java -jar /opt/jmxquery/jmxquery.jar -U service:jmx:rmi:///jndi/rmi://spotfirewin75.cyberdyne.corp:1099/jmxrmi -O 'java.lang:type=GarbageCollector,name='\''PS' 'MarkSweep'\''' -A LastGcInfo -K GcThreadCount
**JMX CRITICAL - java.lang:type=GarbageCollector,name='PS**

As you can see it's chopped off the rest of the command after PS.

How do I get the script to substitute correctly?

  • 1
    I don't see anything chopped but I don't see ${SERVICE_URL} being defined anywhere. – Julie Pelletier Sep 2 '16 at 8:17
  • @Julie the variables are defined, I've put them in my post now. – Aditya K Sep 2 '16 at 8:33
  • @drewbenn I get a different result saying the command line options are not recognised. – Aditya K Sep 2 '16 at 8:33
  • 1
    I think this problem can be simplified. Consider: 'command="ls -l '/tmp/test/My Directory'" $command ' Upon running this I then get: ' ls: cannot access '/tmp/test/My: No such file or directory ls: cannot access Directory': No such file or directory ' I'm pretty sure if I can solve this problem, i can solve the issue I'm facing. – Aditya K Sep 2 '16 at 9:34

When you do this (paraphrasing your shorter example in the comment):

mkdir "foo bar"
parms="-l 'foo bar'"
ls $parms

The parms variable is word-split along any whitespace, without regard to the quotes, so it becomes -l, 'foo, and bar' (three arguments). The original example had the same issue with attr_marksweep_threadcount, and ended up with one of the arguments containing java.lang:type=GarbageCollector,name='PS and the rest of the quoted string in another argument. I'll assume your java didn't like that.

If we quote the variable containing the parameters:

ls "$parms"

We get ls called with -l 'foo bar' (one argument). Quoting the variable prevents word-splitting (and filename globbing), but quotes inside the variable don't.

It's a bit difficult to work around this problem with simple shell variables, but since Bash has arrays, you could use one and put each argument in a separate element of the array:

array=("-l" "foo bar")
ls "${array[@]}"

"${array[@]}" expands to the equivalent of all the array members, individually quoted.

With array-less shells, you have to use some work-arounds. The positional parameters can be expanded with $@ similarly to arrays:

set -- "-l" "foo bar"
ls "$@"

Or, since word-splitting is done only along characters set in IFS, we can make the shell split on something other than white-space.

parms='-l#foo bar'
ls $parms
# though IFS stays set to the hash sign after this

The output from bash -x in your example tries to show what happens, but since it tries to show in single-quotes a string containing a single-quote, the output is a bit messy. This: 'java.lang:type=GarbageCollector,name='\''PS' parses as 'java.lang:type=GarbageCollector,name=', \', and 'PS' all concatenated together, i.e. two single-quoted strings, and a quoted single-quote. Which looks prettier in double-quotes: "java.lang:type=GarbageCollector,name='PS".

| improve this answer | |

Try replacing:

attr_marksweep_threadcount="-O java.lang:type=GarbageCollector,name='PS MarkSweep' -A LastGcInfo -K GcThreadCount"


attr_marksweep_threadcount='-O java.lang:type=GarbageCollector,name="PS MarkSweep" -A LastGcInfo -K GcThreadCount'
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.