다음과 같은 if 문이 있다고 가정합니다.
if [ $(false) ]; then
echo "?"
fi
그러면 "?"가 인쇄되지 않습니다(조건이 거짓임). 그런데 다음과 같은 경우에는 "?!"가 출력되는데 왜 그럴까요?
if [ $(false) -o $(false) ]; then
echo "?!"
fi
답변1
$(false)
false로 평가되지 않으며 빈 문자열을 생성합니다. 인용이 없기 때문에,
if [ $(false) ]; then
다음과 같이 평가됨
if [ ]; then
[
빈 표현식은 거짓 이므로 이는 거짓입니다 .
if [ $(false) -o $(false) ]; then
다음과 같이 평가됨
if [ -o ]; then
이것아니요-o
연산자를 사용하면 -o
단일 문자열이 포함된 표현식으로 평가됩니다. [
이러한 표현식은 true이므로 then
문의 일부가 if
실행됩니다.
바라보다POSIX 사양test
, 특히:
연산자 우선 순위와 생성되어야 하는 반환 값을 결정하는 데 사용되는 알고리즘은 테스트할 인수 수를 기반으로 합니다. (단, "[...]" 형식을 사용하는 경우 마지막 매개변수 <오른쪽 대괄호>는 알고리즘에 포함되지 않아야 합니다.)
다음 목록에서 $1, $2, $3 및 $4는 테스트할 매개변수를 나타냅니다.
인수 0개:
false(1)를 종료합니다.
매개변수 1개:
$1이 null이 아니면 true(0)를 반환하고, 그렇지 않으면 false를 반환합니다.
test
연산자는 두 개 이상의 인수가 제공되는 경우에만 고려됩니다.
명령의 종료 상태를 조건으로 사용하려면 명령 대체 또는 다음 항목에 넣지 마십시오 [ ]
.
if false; then
그리고
if false || false; then
또한 참고하세요test
-a
연산자는 -o
더 이상 사용되지 않으며 신뢰할 수 없습니다.;쉘의 &&
AND ||
연산자를 사용해야 합니다.예를 들어
if [ "$a" = b ] || [ "$a" = c ]; then
답변2
훌륭한 답변에서 지적한 내용을 반복하지 않겠습니다.작성자: @StephenKitt그리고@ilkkachu여기서는 글쓰기의 의미에만 초점을 맞춥니다 if [ $(cmd) ]; then...
.
우선 이게 [
아니라는 점 알아두세요POSIXsh
연산자라고도 하는 별도의 유틸리티입니다.test
, 여기서 문법의 //// 문 if
부분 에 사용됩니다.if
then
elif
else
fi
sh
언어.
그 임무는 인수를 조건식으로 평가하는 것입니다. 예를 들어 [
, a
, =
, b
및 ]
를 매개변수로 받거나 test
, a
, =
및 을 받으면 b
다음과 같이 해석하므로 false/실패한 종료 상태를 반환합니다."'a'와 'b'는 같은 문자열인가요?"조건식.
[
일반적으로 // 명령문의 일부로 사용되거나 if
// 또는 // 명령문 내의 유일한 명령으로 사용되지만 이러한 명령문일 필요도 없고 단일 명령을 호출할 필요도 없습니다.if
then
elif
else
fi
while
do
done
until
do
done
[
실행은 를 사용하고 , 결과를 확장 하고, 명령을 별도의 인수로 호출하는 것을 [ $(cmd) ]
의미합니다 . 그런 다음 이러한 매개변수는 조건식으로 해석되고 결과에 따라 true 또는 false를 반환합니다(또는 표현식을 이해할 수 없는 경우 false).[
[
$(cmd)
]
[
POSIX sh에서는 $(cmd)
모든 후행 개행 문자를 제거하여 표준 출력으로 확장하며 cmd
, 따옴표가 없고 목록 컨텍스트에 있으므로 IFS 분할 후 와일드카드가 적용됩니다(해당 출력에 NUL 문자가 있는 경우 동작은 지정되지 않습니다).
그래서 if [ $(cmd) ]
또는 test $(cmd)
아무 의미가 없습니다.
그것은 질문을 하는 것과 같습니다:"분할+글로브되면 출력이 cmd
true로 평가되는 유효한 조건식을 구성합니까?"
예를 들어 cmd
출력 합계에 우연히 포함되어 있고 a,*
현재 작업 디렉터리에 두 개의 파일(하나는 이름이 지정 되고 다른 하나는 이름이 지정됨 ) 이 포함된 경우 해당 파일은 인수로 , , , 를 사용 하여 호출됩니다. 다행히 이는 유효한 조건식이지만 false를 반환하는 조건식 은 그렇지 않습니다 .$IFS
,
=
b
[ $(cmd) ]
[
[
a
=
b
]
a
b
$ cd "$(mktemp -d)"
$ touch = b
$ cmd() { echo 'a,*'; }
$ IFS=,
$ set -o xtrace
$ if [ $(cmd) ]; then echo yes; else echo no; fi
++ cmd
++ echo 'a,*'
+ '[' a = b ']'
+ echo no
no
이제 [ "$(cmd)" ]
더 의미가 있습니다. Quote 명령 대체는 NUL을 출력할 때 지정되지 않은 상태로 남아 있는 후행 개행 문자의 제거를 방지하지 않지만 cmd
, 분할+glob 및 null 제거를 방지합니다. 따라서 [
3개의 인수가 항상 전달됩니다: , , [
후행 줄 바꿈이 제거된 출력 및 . 옆에는 해당 매개변수가 빈 문자열이 아닌 경우에만 true를 반환하는 매개변수가 있습니다. 이는 와 동일합니다.cmd
]
[
]
[
[ -n "$(cmd)" ]
그래서 그것은 다음과 같이 말하는 것과 같습니다:" cmd
개행 문자(또는 NUL)가 아닌 문자를 하나 이상 출력하십시오.". 텍스트를 출력하는 명령의 경우(텍스트가 줄로 구성되고 NUL을 포함하지 않음이 보장됨)cmd
" 공백이 아닌 라인을 하나 이상 출력 하시겠습니까 ?"
짧은 출력을 제외하면 전체 출력을 읽고 에 전달하기 전에 메모리에 저장하게 되므로 비효율적인 방식으로 이 작업을 수행합니다 [
.
if cmd | grep -q .; then...
grep
종료되므로 더 효율적입니다.진짜적어도 하나의 문자를 포함하는 줄을 찾으면.
그렇다면 결국 쉘이 충돌하게 됩니다 cmd
.yes
if [ "$(cmd)" ]
충분한 저장오류가 발생하면 if cmd | grep -q .
yes가 즉시 출력됩니다( yes
SIGPIPE 신호에 의해 종료됩니다).
성공 여부 를 테스트하려면 cmd
출력 여부에 관계없이 다음을 수행하면 됩니다.
if cmd; then
echo cmd succeeded
else
echo cmd failed
fi
if $(cmd); then
말도 안되는 또 다른 코드 예제입니다. 그러나 cmd
존재하는 예는 조금 다릅니다 false
.
다시 말하지만, $(cmd)
후행 개행 문자는 제거되어 분할+글로브의 영향을 받습니다. 그러나 이번에는 생성된 단어가 [
/ test
유틸리티에 전달되지 않고 이러한 단어 중 첫 번째 단어(있는 경우)가 실행될 명령으로 처리되고 모든 단어가 인수로 전달됩니다.
따라서 cmd
출력 echo:hello:world
및 $IFS
포함이 인수 로 및 인수로 실행 되고 stdout에 성공적으로 쓸 수 있다고 가정하면 true :
/ 성공을 반환하므로 해당 부분 이 실행됩니다.echo
echo
hello
world
echo
"hello world\n"
then
이제 cmd
출력이 생성되지 않거나 줄 바꿈 및 IFS 공백 문자만 생성되면 $(cmd)
단어가 전혀 생성되지 않으므로 다른 명령은 실행되지 않으며 이 시점에서는 cmd
명령문의 종료 상태가 중요합니다 if
.
존재하다:
if $(false); then
echo yes
else
echo no
fi
no
출력이 false
생성되지 않았기 때문에 명령이 실행되지 않았기 때문에 출력되고 종료 상태 에 따라 해당 섹션이 실행되는지 여부 false
가 결정됩니다 .else
존재하다:
if $(echo true; false); then
echo yes
else
echo no
fi
, 또는 문자를 포함 $IFS
하지 않는 것으로 가정되며 결국 실행되고 종료 상태가 명령문 내의 분기를 결정합니다.t
r
u
e
true
if