所以我有一个像:
这样的数组al_ap_version=('ap_version' '[[ $data -ne $version ]]')
条件在循环中得到评估,如:
for alert in alert_list; do
data=$(tail -1 somefile)
condition=$(eval echo \${$alert[1]})
if eval "$condition" ; then
echo SomeAlert
fi
done
虽然这通常适用于许多场景,但如果$ data返回类似“ - / - ”或“4.2.9”的内容,我会收到错误,因为它似乎不喜欢变量中的复杂字符串。
显然我不能将变量括在单引号中,因为它不会扩展所以我想要扩展$ data变量(或者实际上是版本的var,它会遭受同样的可能命运)评估可以处理?
答案 0 :(得分:1)
忽略eval
在这里使用可能非常危险的事实(除非somefile
中的数据由您控制且仅由您控制),您的示例代码中有一些问题需要解决。
在for
循环中,alert_list
必须为$alert_list
。
另外,正如@choroba所指出的那样,您应该使用!=
而不是-ne
,因为您的输入并不总是整数。
最后,在调试时,您可以将set -x
添加到脚本的顶部,或将-x
添加到shebang行的末尾以启用详细输出(有助于确定bash如何扩展您的变量)。
这对我有用:
#!/bin/bash -x
data=2.2
version=1
al_ap_version=('ap_version' '[[ $data != $version ]]')
alert_list='al_ap_version'
for alert in $alert_list; do
condition=$(eval echo \${$alert[1]})
if eval "$condition"; then
echo "alert"
fi
done
答案 1 :(得分:1)
你可以尝试一种更实用的方法,即使bash只是勉强能够做到这一点。总的来说,将要执行的动作打包到bash函数并使用函数名称引用它通常要容易得多,而不是试图将动作保持为要评估的字符串。
但首先,使用数组名称数组很尴尬。让我们摆脱它。
我不清楚数组ap_version
中元素0 al_ap_version
}的要点,但我认为它与错误消息有关。如果警报处理的顺序不重要,您可以用单个关联数组替换数组名称列表:
declare -A alert_list
alert_list[ap_version]=... # see below
alert_list[os_dsk]=...
然后用:
处理它们for alert_name in ${!alert_list[@]}; do
alert=${alert_list[$alert_name]}
...
done
这样做之后,我们可以通过为每个警报创建一个bash函数来摆脱eval,因此对于杂耍引号具有丑陋的必要性:
check_ap_version() {
(($version != $1))
}
修改:似乎$1
不一定是数字,因此最好使用非数字比较,但确切的版本匹配可能不是您的'在任何一个之后。所以也许最好使用:
check_ap_version() {
[[ $version != $1 ]]
}
注意函数的第一个参数是数据值的约定。
现在我们可以将函数的名称插入alert数组,并在循环中间接调用它:
declare -A alert_list
alert_list[ap_version]=check_ap_version
alert_list[os_dsk]=check_op_dsk
check_alerts() {
local alert_name alert
local data=$(tail -1 somefile)
for alert_name in ${!alert_list[@]}; do
alert=${alert_list[$alert_name]}
if $alert "$data"; then
signal_alert $alert_name
fi
done
}
如果您准备对函数名称更加严格,则可以避免关联数组,从而按顺序处理警报。例如,假设每个函数都具有名称check_<alert_name>
。然后上面可能是:
alert_list=(ap_version os_dsk)
check_alerts() {
local alert_name
local data=$(tail -1 somefile)
for alert_name in $alert_list[@]; do
if check_$alert_name "$data"; then
signal_alert $alert_name
fi
done
}