我只编写了几个星期的脚本,我已经设法在这篇文章的底部编写脚本并让它运行。但是,我知道我真正需要做的是将底部的 if 语句条件移动到上面的 if 语句中。所以我需要做这样的条件:
如果文件存在(并且不是空字符串)并且是以下两个之一:(“switchport mode access”或“switchport trunk allowed vlan”)。
我觉得如果我做了类似下面的事情(不确定语法是否正确,但没关系,因为我只是在解释):
###### 1 ##### ################ 2 #################### ######## 3 ########
if ([ ! -z "${prev}" ] && [ "$line" = "switchport access vlan $i" ] || [[ $line =~ $regex ]]);then
然后我担心我不明白它是如何分组的。因此,如果我们将每个条件称为 1、2、3。那么这是否意味着条件 1&2 OR 3。或者这个人条件 1 & (2-OR-3)?就像,有没有一种方法可以通过在要分组的位周围加上括号来消除任何歧义,就像您在数学中所做的那样。正确的做法是什么?
tmpfiles="$PWD/configs/*.tmp"
prev=
for basefile in $tmpfiles
do
while read line
do
## get old vlans and interfaces
for i in "${oldvlans[@]}"
do
if ([ ! -z "${prev}" ] && [ "$line" = "switchport access vlan $i" ]);then
line1="${prev}"
line2="${line}"
echo "${line1}"
echo "${line2}"
fi
done
### check for lines with "trunk allowed vlans" on and do a no trunk allowed vlan on them
regex="switchport trunk allowed vlan*"
if [ ! -z "${prev}" ] && [[ $line =~ $regex ]];then
line1="${prev}"
line2="${line}"
echo "${line1}"
echo "no ${line2}"
fi
prev="${line}"
done < "$basefile" > "$basefile.done"
编辑:我在下面做了一些测试来尝试找出逻辑,因为 stephane 说 () 不是用于分组测试条件,我相信我证明了他/她错了):
$ var1=sumit ; [ -z "var1" ] && ([ "$var1" = "sxxt" ] || [ "$var1" = "sumit" ]); echo $?
1
$ var1=sumit ; [ -n "var1" ] && ([ "$var1" = "sxxt" ] || [ "$var1" = "sumit" ]); echo $?
0
所以我认为这是在我想要的地方进行测试的正确方法:
If [condition1] AND if ([condition 2] OR [condition 3] are true).
但我只是在胡说八道,只需要尝试澄清一下。
在 bash 中,做你想做的最干净的方法是使用
[[ ]]
构造而不是更有限的构造[ ]
并结合条件:哪个工作如你所料:
现在,您确实可以滥用
( )
在子 shell 中运行测试并检查结果,但它丑陋、复杂且不必要。如果你坚持走这条路,至少要避免使用 subshell 并使用{ }
来对命令进行分组:但实际上,如果您使用的是 bash,那就选择
[[ ]]
. 如果使用 POSIX shell,您可以使用-o
:关于这部分:
shell 没有命令列表
&&
中的和的优先级(如上),但从左到右解析它们。所以如果你有,它会被有效地分组为。同样,是。||
A && B || C
(A && B) || C
A || B && C
(A || B) && C
这与大多数其他编程语言不同, where
&&
优先于||
. 更糟糕的是,在[[ .. ]]
条件和算术表达式(例如$(( .. ))
)内部,Bash 也遵守该优先级。所以,这两个是不同的:
(当然
a = a
,a = b
这很愚蠢,但可以作为示例。)最好避免对条件使用命令列表,而是按照其他人的建议和使用
[[ ... ]]
.也就是说,只要您正在运行 Bash 或无论如何都拥有它的其他 shell,因为
[[ ... ]]
这不是标准功能。在标准的 POSIX shell 中,您只能使用命令列表。至于您的代码,我不确定您是否可以通过将这三个条件组合为一个条件来取得很多成就,即使分组正确也是如此:
(无论您是使用子外壳
(foo)
还是复合组{ foo;}
进行分组)主要是因为您拥有它的方式,您必须在
${oldvlans[@]}
循环中同时执行后两个测试,但实际上只有其中一个取决于循环变量。此外,[ ! -z "$prev" ]
条件似乎是while read
循环执行任何操作的先决条件,所以为什么不单独使用它。我宁愿将这三者分开而不是将它们结合起来:
(或者也许首先检查该行是否匹配
switchport access vlan
,switchport trunk allowed vlan
然后再决定要做什么。)请注意,在正则表达式中,
n*
意味着“零个或多个字母n
”,而不是“一个n
后跟任何东西”,就像它在 shell 模式中所做的那样。但是在[[ str =~ regex ]]
测试中,正则表达式无论如何都没有锚定到字符串的开头/结尾(例如[[ foobar =~ ob ]]
是真的),所以你无论如何都不需要尾随的“匹配任何东西”。一些其他编程语言也可能提供比 shell 更好的字符串处理工具。