我有一个脚本,该脚本读取IPSec .conf文件并查找字符串“ conn”,保存连接的名称,然后从包含“ rightsource”的行中获取IP地址。当前,两者之间存在一对一的关系-如果有一行说“ conn example1”,那么只有一行说正确的来源是一个IP地址。当前处理这种情况的脚本部分是:
for CONF in *.conf; do
set +e
declare -a CONNS=($(awk '/^conn/ {print $2}' < $CONF | fgrep -vi common))
declare -a RSOURCES=($(awk -F\= '/(^ *rightsource|^ *# *effectiverightsource)/ {print $2}' < $CONF))
CONN_SIZE=${#CONNS[@]}
SOURCE_SIZE=${#RSOURCES[@]}
if [ $CONN_SIZE != $SOURCE_SIZE ]; then
#echo "Problem: number of connections $CONN_SIZE not equal to number of source IPs $SOURCE_SIZE in $CONF."
#echo "Connections=${CONNS[@]}"
#echo "Source IPs=${RSOURCES[@]}"
continue
fi
我的问题是我想将IPSec conf文件切换为更好的语法。而不是像这样在conn和rightsource之间建立一对一的关系:
conn example79
rightsourceip=44.45.46.79
conn example80
rightsourceip=44.45.46.80
我想使用一种更有效的语法:
conn example
rightsubnets={44.45.46.79/32,44.45.46.80/32}
“ rightsubnets”花括号可以包含1个,2个或更多IP地址,这是我需要传递给脚本其余部分的地址,以便它可以尝试对每个脚本进行ping操作以确保其仍然可用。
我几乎可以了解现有脚本中的awk命令在做什么,但是我不知道如何最好地查找在较新语法中可以找到的可变数量的IP地址。任何建议将不胜感激!
谢谢, 鲍勃
答案 0 :(得分:0)
我的建议是将rightsubnets
添加到您的RSOURCES
行中,然后稍后在脚本中处理一行或更多行。也就是说,如果特定的RSOURCE具有花括号,则将其作为一个或多个子网处理,否则将与今天一样。这是一个最小的更改,扩展了现有代码,可以满足您的新(附加)要求。
我的另一个建议是,您可能已经超出了shell的舒适范围,也许您应该考虑使用python或perl或类似的东西,在那里您可以构建更好的状态机并更可靠地处理每一行。例如,如果某人忘记在给定的连接中放入rightsourceip
,但将其与另一个条目放在一起(这样它就有两个),那可能是一个错误,但是您将无法轻松地告诉壳。 (IPSec可能会遇到这样的问题,可能不够,也可能不够。根据我的经验,像您这样的脚本经常在重新启动依赖于这些conf文件的工具之前运行,因此额外的错误检测很有帮助。)这不是唯一的问题。可以长成一个更健壮的语言更容易掌握的语言,当然还有很多其他语言。它也可以更快,因为它将只浏览每个文件一次,而您的shell脚本则要读取每个文件至少两次。
答案 1 :(得分:0)
本机bash中的一个实现(在调试工具上花费了相当长的时间)可能看起来像:
#!/usr/bin/env bash
case $BASH_VERSION in [123].*) echo "ERROR: Requires bash 4.0 or newer" >&2; exit 1;; esac
PS4=':$LINENO+' # if trace logging is enabled, include line numbers
conn_re='^[[:space:]]*conn[[:space:]]+([^[:space:]].*)$'
rightsource_re='^[[:space:]]*(effective)?right(source|subnet)s?=(.*)$'
multimatch_re='^[{](.*,.*)[}]$'
# read document from stdin, and populate an associative array
declare -A subnets=( )
for conf in *.conf; do : conf="$conf"
conn=''
while IFS= read -r line; do : line="$line"
[[ $line =~ $conn_re ]] && { conn=${BASH_REMATCH[1]}; continue; }
[[ $line =~ $rightsource_re ]] && { subnets[$conn]=${BASH_REMATCH[3]}; }
done <"$conf"
done
[[ $- = *x* ]] && declare -p subnets >&2 # if tracing enabled, log our extracted values.
handle_result() {
local conn=$1 element=$2
element=${element%/32}
echo "For conn $conn, need to handle element $element"
}
# iterate over the associative array, and call the handler for each address
for conn in "${!subnets[@]}"; do : conn="$conn"
rightsource=${subnets[$conn]}
if [[ $rightsource =~ $multimatch_re ]]; then
IFS=, read -r -a elements <<<"${BASH_REMATCH[1]}"
for element in "${elements[@]}"; do
handle_result "$conn" "$element"
done
else
handle_result "$conn" "$rightsource"
fi
done
如果输入:
conn example
rightsubnets={44.45.46.79/32,44.45.46.80/32}
conn next_example
rightsubnets=1.2.3.4
conn third_example
rightsubnets={5.6.7.8,9.10.11.12/32}
...这会发出输出:
For conn example, need to handle element 44.45.46.79
For conn example, need to handle element 44.45.46.80
For conn third_example, need to handle element 5.6.7.8
For conn third_example, need to handle element 9.10.11.12
For conn next_example, need to handle element 1.2.3.4
...但是,您当然可以更改handle_result
功能以执行所需的ping或其他测试。
您可以在https://ideone.com/QrE1Ff上看到上面的代码