2

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:

JAR=/opt/jmxquery/jmxquery.jar
JMXHOST=tomcat.cyberdyne.corp
JMXPORT=1099
SERVICE_URL="service:jmx:rmi:///jndi/rmi://${JMXHOST}:${JMXPORT}/jmxrmi"
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?

4
  • 1
    I don't see anything chopped but I don't see ${SERVICE_URL} being defined anywhere. Sep 2, 2016 at 8:17
  • @Julie the variables are defined, I've put them in my post now.
    – Aditya K
    Sep 2, 2016 at 8:33
  • @drewbenn I get a different result saying the command line options are not recognised.
    – Aditya K
    Sep 2, 2016 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, 2016 at 9:34

2 Answers 2

1

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.

IFS=#
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".

0

Try replacing:

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

with:

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

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .