두 조건을 하나의 조건으로 이동할 수 있나요?

두 조건을 하나의 조건으로 이동할 수 있나요?

저는 몇 주 동안만 스크립트를 작성했지만 이 게시물의 맨 아래에서 작동하도록 관리했습니다. 하지만 나는 내가 무엇을 해야 하는지 알고 있다진짜다음 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와 마찬가지로) 어쨌든 후행 "아무것도 일치"가 필요하지 않습니다.

일부 다른 프로그래밍 언어도 셸보다 더 나은 문자열 처리 기능을 제공할 수 있습니다.

관련 정보