Bash 脚本未按预期替换变量

Bash 脚本未按预期替换变量

我正在尝试编写一个 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'

相关内容