我有一个
sh
(POSIX) 脚本,我试图从主机列表 (SSH) 中选择一个主机,该列表在主机名称中包含一些有趣的信息,例如可用的可用内存、已连接的用户。 .我希望我的脚本的用户选择脚本应考虑哪些特征,以便从所述列表中选择合适的主机。
由于此特征是可选的,因此我的想法是根据用户选择的选项在 shell 变量(仅文本)中构建条件语句。然后,将此变量传递给 AWK 以提取那些合适的主机并随机选择其中之一。目前,saild 语句或
FILTER
可能如下所示:
FILTER='$6 <=MAXUSERS && $7 <=MAXUSERS'
FILTER='$6 <=MAXUSERS && $7 <=MAXUSERS && $9 >=10'
FILTER='$6 <=MAXUSERS && $7 <=MAXUSERS && $9 >=10 && $11 >=8'
($X 只是位置参数,作为主机的特征,我知道它们的位置,只要 HTML 源代码不改变,就不应该改变)我用这段代码构建这些语句:
setUpFilter(){
FILTER='$6 <=MAXUSERS && $7 <=MAXUSERS'
if [ -n "$CPUNUM" ]; then
FILTER="${FILTER} && \$9 >=$CPUNUM"
fi
if [ -n "$FREEMEM" ]; then
FILTER="${FILTER} && \$12 >=$FREEMEM"
fi
}
一旦构建了语句,我就使用这个:
filterHosts(){
setUpFilter
for HOST in $(echo "$AVAILABLEHOSTS"); do # $AVAILABLEHOSTS is a list with only the hosts names
HOSTDATA=$(echo "$REPORTCLEAN" | egrep -A 11 "$HOST") # Report clean is a list of hosts and its data extracted from an HTML file
FILTEREDHOSTS=${FILTEREDHOSTS}$(echo $HOSTDATA | awk -v FILTER="$FILTER" -v MAXUSERS=5 '{
if (FILTER)
print $1 "\\n"
}')
done
}
然而,这并没有按预期工作,因为“过滤器”似乎什么也没做,因为所有主机都存储在
$FILTEREDHOSTS
中,就像所有迭代中的条件都是 true
一样(我不确定为什么),但是当我在 AWK 脚本中手动设置条件时,“过滤器”按预期工作:
filterHosts(){
setUpFilter
for HOST in $(echo "$AVAILABLEHOSTS"); do # $AVAILABLEHOSTS is a list with only the hosts names
HOSTDATA=$(echo "$REPORTCLEAN" | egrep -A 11 "$HOST") # Report clean is a list of hosts and its data extracted from an HTML file
FILTEREDHOSTS=${FILTEREDHOSTS}$(echo $HOSTDATA | awk -v MAXUSERS=5 '{
if ($6 <=MAXUSERS && $7 <=MAXUSERS && $9 >=10)
print $1 "\\n"
}')
done
}
$HOSTDATA
看起来像这样,顺便说一句:HOSTNAME PARAM2 PARAM3 ... PARAM12
,所以我想根据与某些值匹配的一些参数来检索$1
(主机名)。
我知道第二段代码有效,因为我在执行它后手动检查了列表。
我尝试过 AWK 打印
FILTER
,显然该声明是正确的,因为它的打印效果就像我上面写的第一个示例一样,没有任何扩展或意外的东西,就像示例一样。
我不太擅长 AWK,所以我不知道会发生什么,我什至不确定这是否是 AWK 的问题。另一方面,我想知道这是否是我想要实现的目标的最佳方法。
提前致谢。
更新
正如一些用户建议的那样,我将内置的“过滤器”移至 awk 脚本本身,所以我最终得到了这个:
filterHosts(){
for HOST in $(echo "$AVAILABLEHOSTS"); do
HOSTDATA=$(echo "$REPORTCLEAN" | egrep -A 11 "$HOST")
FILTEREDHOSTS=${FILTEREDHOSTS}$(echo $HOSTDATA | awk -v cpunum="$CPUNUM" -v freemem="$FREEMEM" -v MAXUSERS="$1" '{
filter = $6 <=MAXUSERS && $7 <=MAXUSERS
if (length(cpunum) != 0)
filter = filter && $9 >= cpunum
if (length(freemem) != 0)
filter = filter && $12 >= freemem
if (filter)
print $1 "\\n"
}')
done
}
显然,乍一看,这没有问题,所以我认为这个问题“半解决”,因为我不确定为什么前面的代码不起作用,但我有一段不同的代码可以工作。
您的“半最终”解决方案受到无用使用
echo
的困扰,可以重构为
filterHosts(){
for host in $AVAILABLEHOSTS; do
hostdata=$(echo "$REPORTCLEAN" | egrep -A 11 "$host")
filteredhosts=${filteredhosts}$(echo $hostdata |
awk -v cpunum="$CPUNUM" -v freemem="$FREEMEM" -v MAXUSERS="$1" '{
filter = $6 <=MAXUSERS && $7 <=MAXUSERS
if (length(cpunum) != 0)
filter = filter && $9 >= cpunum
if (length(freemem) != 0)
filter = filter && $12 >= freemem
if (filter)
print $1 "\\n"
}')
done
}
echo $hostdata
周围缺少引号会将 egrep
结果扁平化到单行上,这通常是一个错误;但如果无法访问这些数据,我无法相应地重构 Awk 脚本。
https://stackoverflow.com/questions/673055/ Correct-bash-and-shell-script-variable-capitalization解释了为什么所有变量都使用小写。理想情况下,脚本的其余部分应该类似地重构。