test 또는 [를 사용하여 논리적 NOT !가 포함된 조건식을 평가할 때 느낌표를 대괄호 내부에 배치해야 합니까, 아니면 외부에 배치해야 합니까?

test 또는 [를 사용하여 논리적 NOT !가 포함된 조건식을 평가할 때 느낌표를 대괄호 내부에 배치해야 합니까, 아니면 외부에 배치해야 합니까?

bash test또는 내장 명령을 사용하여 [논리적 NOT을 사용하여 조건식을 평가할 때 !느낌표를 대괄호 내부에 배치해야 합니까, 아니면 외부에 배치해야 합니까? 그게 그렇게 중요한 건가?

이것은 간단한 MRE입니다.

$ var=1
$ if [ $var -gt 0 ]; then echo "evaluated to true"; else echo "evaluated to false";  fi
evaluated to true
$ if ! [ $var -gt 0 ]; then echo "evaluated to true"; else echo "evaluated to false";  fi
evaluated to false
$ if [ ! $var -gt 0 ]; then echo "evaluated to true"; else echo "evaluated to false";  fi

답변1

! [ "$var" -gt 0 ][ ! "$var" -gt 0 ]오류가 없는 한 현재 쉘과 유틸리티는 중요하지 않습니다.


하지만 따옴표 if ! [ $var -gt 0 ]없이 썼다는 점에 유의하세요.if [ ! $var -gt 0 ]$var정말 중요한!

$var비어 있거나 공백이 포함되어 있으면 중단됩니다. 예를 들어 다음과 같은 내용이 표시됩니다 if ! [ -gt 0 ]. 테스트에서 [오류 메시지가 인쇄되고 잘못된 종료 코드 2가 반환됩니다. 그러면 반전되어 !전체 조건이 참이 됩니다!

$ var=
$ if ! [ $var -gt 0 ]; then echo yes; fi
bash: [: -gt: unary operator expected
yes

특정 상황에서는 [ ! $var -gt 0 ]거짓 오류 반환이 거짓으로 유지되고 분기가 수행되지 않으므로 더 안전한 것으로 간주될 수 있습니다. 그러나 여기서 가장 즉각적인 문제는 쉽게 고칠 수 있는 따옴표가 없다는 것입니다.

견적은 다음을 참조하세요.언제 큰따옴표가 필요합니까?


그러나 인용 문제와 별개로 에 숫자가 아닌 값이 있으면 $var오류가 발생 [하고 조건이 거짓이 됩니다. 따라서 입력이 유효한지 미리 테스트하거나 이 가능성을 처리해야 합니다. 경우에 따라 오류가 발생했을 때 올바른 조치는 다음과 같습니다.가져가다예를 들어, 오류 종료가 포함된 경우 분기입니다. 불행하게도 쉘에는 예외 등이 없기 때문에 실제로 오류를 감지하는 좋은 방법이 없습니다. 오류와 잘못된 결과를 구별하려면 $?원래 값을 저장하고 참조해야 합니다.

또는 오류 조건이 적절한 결과와 일치하도록 테스트를 작성할 수 있습니다. 예를 들어 여기 테스트는 대신 추가 부정을 사용하여 작성되었지만 [ "$1" -le 0 ]잘못된 입력으로 인해 오류 종료가 발생한다는 이점이 있습니다. 이것은 !외부에서만 작동합니다 [.

$ cat foo.sh
#!/bin/bash

if ! [ "$1" -gt 0 ]; then
    echo "invalid input '$1'"
    exit 1
fi
echo "doing work on '$1'"

$ bash foo.sh
foo.sh: line 3: [: : integer expression expected
invalid input ''

변수 값의 변경 및 매트릭스의 다양한 테스트:

   테스트\$n | '0' '1' 'x'     
 ------+------------------ -- ----            
  [“$n”-le 0] |참 또는 거짓(오류 있음)
  [! "$n"-gt 0] | true false false(오류 있음)
! [“$n”-gt 0] |참 또는 거짓    참(오류 있음)

아마도 과거에 [테스트의 피연산자가 연산자처럼 보일 때 혼동을 주었던 버전과 다소 관련이 있을 수 있습니다. 예를 들어, [ ! = x ]the와 같은 것은 !부정으로 처리될 수 있으며 전체 표현식을 구문 분석할 수 없습니다. !내부에 넣는 것이 [문제를 복잡하게 만들지 않을까 걱정할 수도 있지만 실제로 그런 일이 일어날지는 모르겠습니다. 그럼에도 불구하고 POSIX 호환 버전 은 [적어도 .-a-o

바라보다:쉘 변수를 문자열 리터럴과 비교할 때 양쪽에 접두사를 추가하는 목적은 무엇입니까?, 특히 Stéphane의 탁월한 답변(이 예를 사용했습니다 [ ! = x ]).

답변2

예, 그것은 중요합니다.

!외부에 배치하면 [ ... ]모든 오류가 무시됩니다.

var=nono

if ! [ "$var" -gt 0 ]; then echo YES; fi
bash: [: 0.1: integer expression expected
YES

if [ ! "$var" -gt 0 ]; then echo YES; fi
bash: [: 0.1: integer expression expected

if ! command; then ...이는 종료 상태가 0이 아닌 경우 일치가 발생하고 명령은 command오류 시 및 false 로 평가되는 경우 [ expr ]모두 0이 아닌 종료 상태를 갖기 때문입니다 .expr

bash가 아닌 ksh에서만 두 가지가 유사합니다. ksh에서는 숫자가 아닌 변수가 0해당 컨텍스트에서 오류가 아닌 변수로 처리되기 때문입니다.

답변3

평가 대상에 관심이 있는 경우에만 중요합니다 . 유틸리티의 오류를 고려 !하면 수행할 수 있습니다 (예: 실제로 정수가 아닌 경우 유틸리티가 실패하고 종료 상태가 0이 아님). 테스트는 다음과 같이 평가됩니다.[$var[잘못된그러나 유틸리티가 테스트를 실행하지 못했기 때문입니다.)

in 은 if [ ! "$var" -gt 0 ]; then ...; fi인수 !이므로 [유틸리티에 의해 평가되어 [적절한 종료 상태로 종료되기 전에 테스트의 의미를 내부적으로 무효화합니다. ( $var정수가 아닌 경우 테스트가 실패하고 분기가 수행되지 않습니다.)

에서 쉘은 if ! [ "$var" -gt 0 ]; then ...; fi명령문에 유틸리티를 사용하기 전에 유틸리티의 종료 상태를 억제합니다(0과 0이 아닌 값 사이에서 전환). (정수가 아닌 경우 테스트는 실패하고 쉘은 0이 아닌 종료 상태를 무효화하고 다음과 같이 해석합니다.[if$var진짜, 지점이 채택됩니다. )

이 간단한 테스트의 경우 코드를 더 쉽게 읽고 이해할 수 있도록 테스트를 다시 작성하고 [ "$var" -le 0 ]필요한 경우 $var정수 유효성 검사를 사용합니다.

관련 정보