我正在尝试编写一个 shell 脚本,它使用名为 jmxquery 的命令
这是在命令行上起作用的:
[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**
如您所见,我得到了带有线程计数详细信息的 JMX OK。所以我试图在 shell 脚本中做同样的事情。我有一个这样定义的变量:
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"
然后我运行:
java -jar ${JAR} -U ${SERVICE_URL} $attr_marksweep_threadcount
这是 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**
正如你所看到的,PS 之后的命令的其余部分被砍掉了。
如何让脚本正确替换?
答案1
当你这样做时(解释一下评论中较短的示例):
mkdir "foo bar"
parms="-l 'foo bar'"
ls $parms
变量parms
是分词沿着任何空白,不考虑引号,所以它变成
-l
, 'foo
, and bar'
(三个参数)。最初的示例与 , 存在同样的问题attr_marksweep_threadcount
,最终导致其中一个参数包含java.lang:type=GarbageCollector,name='PS
另一个参数中引用的字符串的其余部分。我假设你的java不喜欢这样。
如果我们引用包含参数的变量:
ls "$parms"
我们被ls
叫来-l 'foo bar'
(一个参数)。引用变量可以防止分词(和文件名通配),但引号里面变量没有。
使用简单的 shell 变量来解决这个问题有点困难,但由于 Bash 已经数组,您可以使用一个并将每个参数放入数组的单独元素中:
array=("-l" "foo bar")
ls "${array[@]}"
"${array[@]}"
扩展为相当于所有数组成员(单独引用)。
对于无数组 shell,您必须使用一些解决方法。这位置参数可扩展为$@
与数组类似:
set -- "-l" "foo bar"
ls "$@"
或者,由于分词仅沿着 中设置的字符完成IFS
,因此我们可以使 shell 在除空白之外的其他内容上进行分割。
IFS=#
parms='-l#foo bar'
ls $parms
# though IFS stays set to the hash sign after this
示例中的输出bash -x
尝试显示发生的情况,但由于它尝试在单引号中显示包含单引号的字符串,因此输出有点混乱。这:
'java.lang:type=GarbageCollector,name='\''PS'
解析为'java.lang:type=GarbageCollector,name='
、\'
、 以及'PS'
所有连接在一起的内容,即两个单引号字符串和一个带引号的单引号。用双引号看起来更漂亮:"java.lang:type=GarbageCollector,name='PS"
.
答案2
尝试更换:
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'