Estou fazendo scripts há apenas algumas semanas e consegui escrever o script no final desta postagem e fazê-lo funcionar. No entanto, sei que o que realmente preciso fazer é mover a condição inferior da instrução if para a instrução if acima. Então eu preciso fazer uma condição como esta:
Se o arquivo existir (e não for uma string vazia) E for um destes 2: ("acesso ao modo switchport" OU "vlan permitido pelo tronco switchport").
Eu sinto que se eu fizesse algo como o abaixo (não tenho certeza se a sintaxe está correta, mas não importa porque estou apenas explicando):
###### 1 ##### ################ 2 #################### ######## 3 ########
if ([ ! -z "${prev}" ] && [ "$line" = "switchport access vlan $i" ] || [[ $line =~ $regex ]]);then
Então estou preocupado, não entendo como isso o agrupa. Então, se chamarmos cada condição de 1,2,3. Então, isso significa condição 1 e 2 OU 3. Ou este homem condiciona 1 e (2-OU-3)? Tipo, existe uma maneira de esclarecer qualquer ambiguidade, como você faria na matemática, colocando colchetes em volta dos bits que deseja agrupar. Qual é a maneira certa de fazer isso?
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"
EDIT: Fiz alguns testes abaixo para tentar descobrir a lógica, já que stephane disse () não é para agrupar condições de teste e estou confiante de que provei que ele estava errado):
$ var1=sumit ; [ -z "var1" ] && ([ "$var1" = "sxxt" ] || [ "$var1" = "sumit" ]); echo $?
1
$ var1=sumit ; [ -n "var1" ] && ([ "$var1" = "sxxt" ] || [ "$var1" = "sumit" ]); echo $?
0
Então acho que essa é a forma correta de fazer um teste onde eu quero:
If [condition1] AND if ([condition 2] OR [condition 3] are true).
Mas estou apenas cortando e preciso tentar esclarecê-lo.
No bash, a maneira mais limpa de fazer o que você deseja é usar a
[[ ]]
construção em vez da mais limitada[ ]
e combinar as condições:Que funciona como você espera:
Agora, é verdade que você pode abusar do
( )
para rodar os testes em um subshell e checar o resultado mas é feio, complicado e desnecessário. Se você insiste em seguir por esse caminho, pelo menos evite o subshell e use{ }
para agrupar os comandos:Mas, realmente, se você estiver usando o bash, vá para
[[ ]]
. E se estiver usando um shell POSIX, você pode usar-o
:Sobre esta parte:
O shell não tem precedência para
&&
e||
nas listas de comandos (como o acima), mas os resolve da esquerda para a direita. Portanto, se você tiverA && B || C
, ele será efetivamente agrupado como(A && B) || C
. Da mesma forma,A || B && C
é(A || B) && C
.O que não é o mesmo que na maioria das outras linguagens de programação, onde
&&
tem precedência sobre||
. E para piorar, dentro de[[ .. ]]
condicionais e expressões aritméticas (por exemplo$(( .. ))
), essa precedência também é obedecida no Bash.Então, esses dois são diferentes:
(
a = a
ea = b
são bobos, é claro, mas servirão para o exemplo.)Pode ser melhor evitar o uso de listas de comandos para condicionais e, em vez disso, fazer o que outros sugeriram e usar
[[ ... ]]
.Isto é, desde que você esteja executando o Bash ou outro shell que o possua, pois
[[ ... ]]
não é um recurso padrão. Em um shell POSIX padrão, você está limitado a listas de comandos.Quanto ao seu código, não tenho certeza se você conseguiria muito combinando essas três condições em uma condicional, mesmo se agrupadas corretamente:
(independentemente de você usar um subshell
(foo)
ou um grupo composto{ foo;}
para o agrupamento)Principalmente porque do jeito que você tem, você teria que fazer os dois últimos testes dentro do
${oldvlans[@]}
loop, mas apenas um deles realmente depende da variável do loop. Além disso, a[ ! -z "$prev" ]
condição parece uma pré-condição para owhile read
loop fazer qualquer coisa, então por que não tê-la separadamente.Prefiro dividir os três em vez de combiná-los:
(Ou talvez primeiro verifique se a linha corresponde
switchport access vlan
a ouswitchport trunk allowed vlan
e então decida o que fazer.)Observe que, em expressões regulares,
n*
significa "zero ou mais letrasn
", não "um únicon
seguido por qualquer coisa", como acontece nos padrões de shell. Mas, no[[ str =~ regex ]]
teste, o regex não está ancorado no início/fim da string de qualquer maneira (por exemplo,[[ foobar =~ ob ]]
é verdadeiro), então você não precisa desse "corresponder a nada" à direita de qualquer maneira.Algumas outras linguagens de programação também podem fornecer ferramentas melhores para o processamento de strings do que os shells.