我有一个小需求,要在另一个实用程序的包装器脚本中运行存储在另一个配置文件中的命令。我的包装器脚本(下面)适用于配置文件中不使用"runuser"也包括论点。如果命令使用runuser和my "-c"命令包含参数,脚本失败。
包装器脚本
#!/bin/bash
nagios_cmd=$(grep $1 /etc/nagios/nrpe.cfg | awk -F "=" {'print $2'})
exec=$($nagios_cmd)
if [ $? -eq 0 ]
then
#exitok
echo $exec
exit 0
else
#exitcritical
echo $exec
exit 1001
fi
配置文件
command[check_crsdb_state]=sudo /usr/lib64/nagios/plugins/check_crsdb_state
command[check_crsasm_state]=sudo /usr/lib64/nagios/plugins/check_crsasm_state
command[check_ora1_tablespace_apex]=sudo /usr/sbin/runuser -l oracle -c '/check_oracle_tablespace APEX 32000'
command[check_ora1_tablespace_lob1]=sudo /usr/sbin/runuser -l oracle -c '/check_oracle_tablespace LOB1 32000'
脚本运行成功
[root@quo-mai-ora1 /]# ./rmmwrapper.sh check_crsasm_state
OK - All nodes report 'Started,STABLE'
[root@quo-mai-ora1 /]#
失败脚本运行
[root@quo-mai-ora1 /]# ./rmmwrapper.sh check_ora1_tablespace_apex
APEX: -c: line 0: unexpected EOF while looking for matching `''
APEX: -c: line 1: syntax error: unexpected end of file
[root@quo-mai-ora1 /]#
失败脚本运行(使用bash -x)
[root@quo-mai-ora1 /]# bash -x ./rmmwrapper.sh check_ora1_tablespace_apex
++ grep check_ora1_tablespace_apex /etc/nagios/nrpe.cfg
++ awk -F = '{print $2}'
+ nagios_cmd='sudo /usr/sbin/runuser -l oracle -c '''/check_oracle_tablespace APEX 32000''''
++ sudo /usr/sbin/runuser -l oracle -c ''''/check_oracle_tablespace' APEX '32000''''
APEX: -c: line 0: unexpected EOF while looking for matching `''
APEX: -c: line 1: syntax error: unexpected end of file
+ exec=
+ '[' 1 -eq 0 ']'
+ echo
+ exit 1001
[root@quo-mai-ora1 /]#
您可以在bash -x输出中看到,由于某种原因,当执行$nagios_cmd时,它在提供给结果脚本(/check_oracle_tablespace)的多个参数的空格之前放置了单引号。我已经尝试了不同的方法来执行$nagios_cmd(使用反引号代替等。我已经尝试通过修改配置文件来转义空格字符,使其看起来像这样:
command[check_ora1_tablespace_apex]=sudo /usr/sbin/runuser -l oracle -c '/check_oracle_tablespace APEX 32000'
我还尝试在runuser上的-c后面用双引号而不是单引号封装命令,或者根本不使用引号。
我显然忽略了bash的一些根本错误。我怎么能让脚本只是执行$nagios_cmd的内容,因为它出现在纯文本?
这看起来像是eval
实际上是正确答案的罕见情况之一。试试这个:
exec=$(eval "$nagios_cmd")
解释:bash直到解析命令的后期才展开变量,所以变量中的字符串不会像它实际上是命令的一部分那样被解析。在这种情况下,问题是在引号和转义被解析后展开了,所以多单词命令周围的单引号要达到预期效果已经太晚了。参见BashFAQ #50: "我试图将命令放入变量中,但复杂的情况总是失败!">
eval
所做的实际上是从一开始重新运行整个命令解析过程。因此,该变量被展开为您想要运行的命令(包括引号等),并像通常那样进行解析。
注意,我在变量周围加了双引号;这样它就不会像对未加引号的变量引用和那样经过部分解析过程,然后经过完整的解析过程。这种1.5次的解析过程可能会产生罕见但非常奇怪的效果,因此最好避免。
还有:eval
有一个罪有应得的坏名声(我用了"巨大的bug磁铁"这个词);来描述它)。这是因为它从根本上是将数据(例如变量的内容)视为可执行代码,因此很容易发现您正在做的事情,例如将文件名的部分作为命令执行。但是在这种情况下,您的数据应该是命令,并且(希望)被信任不包含恶意、无效等内容。在这种情况下,您希望数据被视为可执行代码。