저는 몇 주 동안만 스크립트를 작성했지만 이 게시물의 맨 아래에서 작동하도록 관리했습니다. 하지만 나는 내가 무엇을 해야 하는지 알고 있다진짜다음 if문의 조건을 위 if문으로 옮기는 것입니다. 따라서 다음과 같은 조건을 수행해야 합니다.
파일이 존재하고(빈 문자열이 아님) 다음 2 중 하나인 경우: ("스위치포트 모드 액세스" 또는 "VLAN에 대한 스위치포트 트렁킹 허용").
다음과 같은 작업을 수행한 것 같은 느낌이 듭니다(구문이 올바른지 확실하지 않지만 단지 설명하는 것이므로 중요하지 않습니다).
###### 1 ##### ################ 2 #################### ######## 3 ########
if ([ ! -z "${prev}" ] && [ "$line" = "switchport access vlan $i" ] || [[ $line =~ $regex ]]);then
그렇다면 그것이 어떻게 그룹화되어 있는지 이해하지 못할까 봐 걱정됩니다. 따라서 각 조건을 1,2,3이라고 부르면 따라서 이는 조건 1&2 또는 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"
편집: Stephen이 ()가 테스트 조건을 그룹화하는 데 작동하지 않는다고 말했고 나는 그/그녀가 틀렸다는 것을 증명했다고 믿기 때문에 논리를 파악하기 위해 아래에서 몇 가지 테스트를 수행했습니다.
$ 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).
하지만 나는 그 문제로 어려움을 겪고 있으며 이를 명확히 하려고 노력해야 합니다.
답변1
Bash에서 원하는 작업을 수행하는 가장 깔끔한 방법은 [[ ]]
더 제한된 구성 대신 구성을 사용 [ ]
하고 조건을 결합하는 것입니다.
if [ ! -z "${prev}" ] && [[ "$line" = "switchport access vlan $i" || "$line" =~ $regex ]];then
효과는 예상한 대로입니다.
$ var1=sumit; [ -z "var1" ] && [[ "$var1" = "sxxt" || "$var1" = "sumit" ]]; echo $?
1
$ var1=sumit; [ -n "var1" ] && [[ "$var1" = "sxxt" || "$var1" = "sumit" ]]; echo $?
0
이제 실제로 ( )
서브셸에서 실행 중인 테스트를 남용하고 결과를 검사할 수 있지만 이는 보기 흉하고 복잡하며 불필요합니다. 이 경로를 계속 사용하려면 최소한 다음을 사용하여 하위 쉘 및 { }
그룹 명령을 사용하지 마십시오.
$ var1=sumit; [ -z "var1" ] && { [ "$var1" = "sxxt" ] || [ "$var1" = "sumit" ] ;}; echo $?
1
$ var1=sumit; [ -n "var1" ] && { [ "$var1" = "sxxt" ] || [ "$var1" = "sumit" ] ;}; echo $?
0
그러나 실제로 bash를 사용하는 경우 [[ ]]
POSIX 쉘을 사용하는 경우 다음을 사용할 수 있습니다 -o
.
$ var1=sumit; [ -z "var1" ] && [ "$var1" = "sxxt" -o "$var1" = "sumit" ] ; echo $?
1
$ var1=sumit; [ -n "var1" ] && [ "$var1" = "sxxt" -o "$var1" = "sumit" ] ; echo $?
0
답변2
이 부분에 관하여:
###### 1 ##### ################ 2 #################### ######## 3 ######## if ([ ! -z "${prev}" ] && [ "$line" = "switchport access vlan $i" ] || [[ $line =~ $regex ]]);then
그렇다면 그것이 어떻게 그룹화되어 있는지 이해하지 못할까 봐 걱정됩니다. 따라서 각 조건을 1,2,3이라고 부르면 따라서 이는 조건 1&2 또는 3을 의미합니다. 아니면 이 사람의 조건이 1 & (2-OR-3)인가요?
&&
쉘에는 다음의 우선순위 가 없습니다 .||
명령 목록에서(위와 같음) 왼쪽에서 오른쪽으로 구문 분석합니다. 따라서 가 있으면 효과적으로 로 A && B || C
그룹화됩니다 (A && B) || C
.A || B && C
(A || B) && C
이는 우선 &&
순위 가 .||
[[ .. ]]
$(( .. ))
따라서 이 두 가지는 다릅니다.
if [[ a = a ]] || [[ a = a ]] && [[ a = b ]]; then
echo one
fi
if [[ a = a || a = a && a = b ]]; then
echo two
fi
( a = a
물론 a = b
이것은 어리석은 일이지만 이 예에서는 이것으로 충분합니다.)
명령 목록을 조건으로 사용하는 것을 피하고 대신 다른 사람들이 제안한 대로 수행하여 사용하는 것이 좋습니다 [[ ... ]]
.
즉, Bash나 해당 기능이 있는 다른 셸을 실행하는 한 이는 [[ ... ]]
표준 기능이 아니기 때문입니다. 표준 POSIX 셸에서는 명령 목록만 사용할 수 있습니다.
귀하의 코드에 관해서는 올바르게 그룹화되었더라도 이 세 가지 조건을 하나로 결합하여 많은 것을 얻을 수 있을지 확신할 수 없습니다.
if [ ! -z "${prev}" ] && ( [ "$line" = "switchport access vlan $i" ] || [[ $line =~ $regex ]] ); then
(그룹화를 위해 서브셸을 사용 (foo)
하는지 복합 그룹을 사용하는지 여부에 관계 없음 { foo;}
)
주로 수행하는 방식에 따라 루프 내부에서 마지막 두 테스트를 수행해야 ${oldvlans[@]}
하지만 실제로는 그 중 하나만 루프 변수에 따라 달라집니다. 또한 [ ! -z "$prev" ]
조건은 루프가 어떤 작업을 수행하기 위한 전제 조건인 것 같으니 while read
단독으로 사용하는 것은 어떨까요?
나는 이 세 가지를 결합하는 것보다 별도로 유지하는 것을 선호합니다.
while read line
do
if [ -z "$prev" ]; then
continue
fi
## we know "$prev" is non-empty now
## get old vlans and interfaces
for i in "${oldvlans[@]}"
do
if [ "$line" = "switchport access vlan $i" ]; then
...
fi
done
### check for "trunk allowed vlans" etc.
regex="switchport trunk allowed vlan"
if [[ $line =~ $regex ]]; then
...
fi
prev="${line}"
done < ...
(또는 해당 줄이 먼저 일치하는지 확인한 다음 무엇을 할지 결정할 수도 switchport access vlan
있습니다 switchport trunk allowed vlan
.)
정규식에서 는 n*
"0개 이상의 문자 n
"를 의미합니다.아니요n
쉘 모드에서와 같이 "단일 다음에 아무 것도 붙지 않음". 그러나 [[ str =~ regex ]]
테스트에서 정규식은 어쨌든 문자열의 시작/끝에 고정되지 않으므로( [[ foobar =~ ob ]]
true와 마찬가지로) 어쨌든 후행 "아무것도 일치"가 필요하지 않습니다.
일부 다른 프로그래밍 언어도 셸보다 더 나은 문자열 처리 기능을 제공할 수 있습니다.