쉘 if 문에서 여러 조건을 나타내는 방법은 무엇입니까?


308

다음과 같은 여러 조건을 나타내고 싶습니다.

if [ ( $g -eq 1 -a "$c" = "123" ) -o ( $g -eq 2 -a "$c" = "456" ) ]   
then  
    echo abc;  
else  
    echo efg;   
fi  

하지만 스크립트를 실행하면

syntax error at line 15: `[' unexpected, 

15 행은 다음과 같은 경우를 보여줍니다.

이 상태에 어떤 문제가 있습니까? 에 문제가있는 것 같습니다 ().


6
쉘 조건이 아니라 테스트 조건 에 대해 묻습니다 . 예제의 전체 표현식 은 쉘이 아닌 test( [) 로 평가됩니다 . 쉘은 종료 상태 만 평가합니다 [.
ceving


답변:


381

고전적인 기술 (메타 문자 이스케이프) :

if [ \( "$g" -eq 1 -a "$c" = "123" \) -o \( "$g" -eq 2 -a "$c" = "456" \) ]
then echo abc
else echo efg
fi

나는에 대한 참조 동봉 한 $g따옴표를; 일반적으로 좋은 습관입니다. 의 우선 순위 때문에 엄밀히 괄호가 필요하지 않습니다 -a-o차종은 심지어 그들없이 수정합니다.

것을 주 -a-o운영자에 대한 POSIX 사양의 일부 test일명, [주로 (그들은의 한 부분 이었기 때문에 이전 버전과의 호환성을 위해, test예를 들어, 7 판 UNIX에서)하지만, 명시 적으로 POSIX에 의해 '퇴화'로 표시됩니다. 배쉬 (참조 조건식 )에 대한 고전과 POSIX 의미를 선점 할 것으로 보인다 -a-o인수를 자신의 다른 사업자와 함께.


약간의주의를 기울이면보다 현대적인 [[연산자를 사용할 수 있지만 Bash와 Korn Shell의 버전이 동일 할 필요는 없습니다.

for g in 1 2 3
do
    for c in 123 456 789
    do
        if [[ ( "$g" -eq 1 && "$c" = "123" ) || ( "$g" -eq 2 && "$c" = "456" ) ]]
        then echo "g = $g; c = $c; true"
        else echo "g = $g; c = $c; false"
        fi
    done
done

Mac OS X에서 Bash 3.2.57을 사용하는 예제 실행 :

g = 1; c = 123; true
g = 1; c = 456; false
g = 1; c = 789; false
g = 2; c = 123; false
g = 2; c = 456; true
g = 2; c = 789; false
g = 3; c = 123; false
g = 3; c = 456; false
g = 3; c = 789; false

변수 는 동일한 방식으로 별도의 명령이 아니기 때문에 변수를 인용 [[할 필요 [가 없습니다 [.


고전적인 질문 아닌가요?

나는 그렇게 생각했을 것입니다. 그러나 다른 대안이 있습니다.

if [ "$g" -eq 1 -a "$c" = "123" ] || [ "$g" -eq 2 -a "$c" = "456" ]
then echo abc
else echo efg
fi

실제로 autoconf도구 또는 관련 패키지에 대한 '휴대용 쉘'지침을 읽으면 ' ||'및 ' &&'을 사용한이 표기법이 권장됩니다. 나는 당신이 심지어까지 갈 수 있다고 생각합니다 :

if [ "$g" -eq 1 ] && [ "$c" = "123" ]
then echo abc
elif [ "$g" -eq 2 ] && [ "$c" = "456" ]
then echo abc
else echo efg
fi

동작이 에코처럼 사소한 경우에는 나쁘지 않습니다. 반복 할 동작 블록이 여러 줄인 경우 반복이 너무 고통스럽고 이전 버전 중 하나가 선호되거나 동작을 다른 then블록 에서 호출되는 함수로 래핑해야합니다 .


9
이스케이프 된 괄호가 작동한다는 것을 아는 것이 좋습니다. 같은 제쳐두고 : 때문에 특히이 경우에, 괄호는 심지어 필요하지 -a실제로보다 높은 우선 순위 갖는다 -o(달리 &&||껍질로 - 그러나, 내부 bash [[ ... ]] 조건문 , && 또한 보다 높은 우선 순위를 가진다 ||). 당신은 피하기 위해 원하는 경우 -a-o최대 견고성과 휴대 - POSIX man 페이지 자체가 제안 - 당신은 또한 사용할 수있는 서브 쉘을 그룹화 :if ([ $g -eq 1 ] && [ "$c" = "123" ]) || ([ $g -eq 2 ] && [ "$c" = "456" ])
mklement0

좋은 해결책이지만 모든 괄호와 괄호가없는 양식을 좋아합니다.if test "$g" -eq 1 -a "$c" = "123" || test "$g" -eq 2 -a "$c" = "456"; then ...
Mogens TrasherDK

나는 이것에 조금 늦었지만 여전히 최고의 검색 결과이므로 다른 언어의 조건부와 비슷하게 동작 &&하거나 ||단락 조건을 사용할 수 있기 때문에 또는를 사용하는 것이 좋습니다. 예를 들면 다음과 같습니다 if [ -n "${check_inodes}" ] && [ "$(stat -f %i "/foo/bar")" = "$(stat -f %i "/foo/baz")" ].. 이 방법을 사용하면 check_inodes비어 있으면 두 번의 호출을 피할 수 stat있지만 더 크고 복잡한 테스트 조건은 실행하기 전에 모든 인수를 처리해야합니다 (이 동작을 잊어 버린 경우에도 버그가 발생할 수 있음).
Haravikk

182

배쉬에서 :

if [[ ( $g == 1 && $c == 123 ) || ( $g == 2 && $c == 456 ) ]]

9
에서 가장 좋은 방법입니다 bash. 따로 :이 특별한 경우에는 내부 [[ ... ]] 조건이 && 실제로는 조건부 외부||달리 우선 순위가 높기 때문에 괄호가 필요하지 않습니다 .
mklement0

어떤 조건이 여기에 맞는지 알아낼 수있는 방법이 있습니까? 첫 번째 괄호 안에 있습니까?
Firelord

1
@Firelord : 반복되는 것을 피하기 위해 조건을 if/ else문 으로 분리하고 코드를 작성 then하고 fi함수를 넣어야합니다. 매우 간단한 경우 case;&폴 스루 (Bash 4)가 포함 된 명령문을 사용할 수 있습니다 .
추후 공지가있을 때까지 일시 중지되었습니다.

1
두 대괄호의 목적은 무엇입니까?
peterchaula


37

/bin/bash다음을 사용 하면 작동합니다.

if [ "$option" = "Y" ] || [ "$option" = "y" ]; then
    echo "Entered $option"
fi

8

문자열 변수에 공백이 있고 존재 여부를 확인하면주의하십시오. 그것들을 올바르게 인용하십시오.

if [ ! "${somepath}" ] || [ ! "${otherstring}" ] || [ ! "${barstring}" ] ; then

1
달러 기호 뒤에 중괄호를 사용할 때 !!
YouAreAwesome

6
$ g=3
$ c=133
$ ([ "$g$c" = "1123" ] || [ "$g$c" = "2456" ]) && echo "abc" || echo "efg"
efg
$ g=1
$ c=123
$ ([ "$g$c" = "1123" ] || [ "$g$c" = "2456" ]) && echo "abc" || echo "efg"
abc

2
쓸모없는 서브 쉘입니다. { ;}대신 사용할 수 있습니다.
phk

2

문자열 비교를 위해 bash에서 다음 기술을 사용할 수 있습니다.

if [ $var OP "val" ]; then
    echo "statements"
fi

예:

var="something"
if [ $var != "otherthing" ] && [ $var != "everything" ] && [ $var != "allthings" ]; then
    echo "this will be printed"
else
    echo "this will not be printed"
fi

0
#!/bin/bash

current_usage=$( df -h | grep 'gfsvg-gfslv' | awk {'print $5'} )
echo $current_usage
critical_usage=6%
warning_usage=3%

if [[ ${current_usage%?} -lt ${warning_usage%?} ]]; then
echo OK current usage is $current_usage
elif [[ ${current_usage%?} -ge ${warning_usage%?} ]] && [[ ${current_usage%?} -lt ${critical_usage%?} ]]; then
echo Warning $current_usage
else
echo Critical $current_usage
fi

3
스택 오버플로에 오신 것을 환영합니다! 이 질문은 단순히 작업 코드가 아닌 설명을 찾고 있습니다. 귀하의 답변은 질문자에 대한 통찰력을 제공하지 않으며 삭제 될 수 있습니다. 관찰 된 증상의 원인을 설명하도록 편집 하십시오 .
Toby Speight

0

두 가지 이상의 조건을 연결할 수도 있습니다.

if [ \( "$1" = '--usage' \) -o \( "$1" = '' \) -o \( "$1" = '--help' \) ]
then
   printf "\033[2J";printf "\033[0;0H"
   cat << EOF_PRINT_USAGE

   $0 - Purpose: upsert qto http json data to postgres db

   USAGE EXAMPLE:

   $0 -a foo -a bar



EOF_PRINT_USAGE
   exit 1
fi
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.