배쉬 인 경우 [false]; true를 반환


151

이번 주 배쉬를 배우고 걸림돌에 부딪쳤다.

#!/bin/sh

if [ false ]; then
    echo "True"
else
    echo "False"
fi

조건이 다르게 표시 되더라도 항상 True를 출력합니다. 괄호 []를 제거하면 작동하지만 그 이유를 이해할 수 없습니다.


3
여기 시작해야 할 것이 있습니다.
keyser

10
BTW,로 시작하는 스크립트 #!/bin/sh는 bash 스크립트가 아닙니다. POSIX sh 스크립트입니다. 시스템의 POSIX sh 인터프리터가 bash에 의해 제공 되더라도 많은 확장 기능이 꺼집니다. bash 스크립트를 작성 하려면 PATH에서 첫 번째 bash 인터프리터를 사용하기 위해 #!/bin/bash또는 이와 동등한 #!/usr/bin/env bash것을 사용하십시오.
Charles Duffy

이것도 영향을 미칩니다 [[ false ]].
CMCDragonkai

답변:


192

당신은 실행 [(일명 test명령을 실행하지, 인수 "거짓"으로) 명령을 false. "false"는 비어 있지 않은 문자열이므로 test항상 명령이 성공합니다. 실제로 명령을 실행하려면 명령을 삭제하십시오 [.

if false; then
   echo "True"
else
   echo "False"
fi

4
거짓 명령 또는 문자열이라는 아이디어는 나에게 이상해 보이지만 작동한다고 생각합니다. 감사.
마일 '29 년

31
bash부울 데이터 유형이 없으므로 true 및 false를 나타내는 키워드가 없습니다. if문은 단지 검사는 당신이 그것을 줄 명령이 성공하거나 실패 할 경우. test명령은 식을 취하고 표현에 해당하는 경우 성공; 비어 있지 않은 문자열은 다른 프로그래밍 언어와 마찬가지로 참으로 평가되는 표현식입니다. false항상 실패하는 명령입니다. (비 true
유적으로

2
if [[ false ]];역시 true를 반환합니다. 그렇습니다 if [[ 0 ]];. 그리고 if [[ /usr/bin/false ]];블록을 건너 뛰지 않습니다. false 또는 0은 0이 아닌 것으로 어떻게 평가할 수 있습니까? 젠장. 중요한 경우 OS X 10.8; Bash 3.
jww

7
false부울 상수 나 0정수 리터럴로 착각하지 마십시오 . 둘 다 그냥 일반 문자열입니다. [[ x ]]에 해당 [[ -n x ]]문자열에 대한 x하이픈으로 시작되지 않습니다. bash없는 어떤 어떤 맥락에서 부울 상수를. 정수와 같은 모양이 같은 내부로 취급되는 문자열 (( ... ))또는 같은 사업자로 -eq또는 -lt내부 [[ ... ]].
chepner

2
@ tbc0, 무언가를 읽는 것보다 더 많은 우려가 있습니다. 변수가 사용자의 통제하에 있지 않은 코드로 설정되거나 외부에서 조작 될 수 있거나 이상한 파일 이름으로 또는 기타로 조작 될 수있는 경우, if $predicate악의적 인 코드를 실행할 if [[ $predicate ]]수없는 방식으로 쉽게 악용 될 수 있습니다 .
Charles Duffy

55

Bash에 대한 빠른 부울 입문서

if문은 인수로 명령을한다 (처럼 &&, ||등). 명령의 정수 결과 코드는 부울 (0 / null = true, 1 / else = false)로 해석됩니다.

test문은 인수로 연산자와 피연산자를 사용 하고 같은 형식의 결과 코드를 반환합니다 if. test명령문 의 별명은 보다 복잡한 비교를 수행 [하는 데 자주 사용됩니다 if.

truefalse문은 아무것도하지 않고 그 결과 코드를 반환 (0과 1, 각각). 따라서 Bash에서 부울 리터럴로 사용할 수 있습니다. 그러나 문장을 문자열로 해석되는 곳에 넣으면 문제가 발생합니다. 귀하의 경우 :

if [ foo ]; then ... # "if the string 'foo' is non-empty, return true"
if foo; then ...     # "if the command foo succeeds, return true"

그래서:

if [ true  ] ; then echo "This text will always appear." ; fi;
if [ false ] ; then echo "This text will always appear." ; fi;
if true      ; then echo "This text will always appear." ; fi;
if false     ; then echo "This text will never appear."  ; fi;

이것은 echo '$foo'vs 와 같은 것을하는 것과 유사합니다 echo "$foo".

test명령문을 사용할 때 결과는 사용 된 연산자에 따라 다릅니다.

if [ "$foo" = "$bar" ]   # true if the string values of $foo and $bar are equal
if [ "$foo" -eq "$bar" ] # true if the integer values of $foo and $bar are equal
if [ -f "$foo" ]         # true if $foo is a file that exists (by path)
if [ "$foo" ]            # true if $foo evaluates to a non-empty string
if foo                   # true if foo, as a command/subroutine,
                         # evaluates to true/success (returns 0 or null)

, 당신은 그냥 패스로 테스트 뭔가 원하는 경우 / (일명 / "true"를 "거짓") 실패, 다음에 명령을 전달 if하거나 &&괄호없이 등 문. 복잡한 비교를 위해서는 적절한 연산자와 함께 대괄호를 사용하십시오.

그리고 그래, 내가 거기 배쉬의 기본 부울 형식 같은 건 없다, 그리고 알고 있어요 if[true기술적으로 "명령"이 아니라 "문"이다; 이것은 매우 기본적인 기능 설명입니다.


1
참고로, 당신은 당신의 코드에 거짓 사실로 1/0을 / 사용하려는 경우,이 if (( $x )); then echo "Hello"; fi표시에 대한 메시지 x=1만하지 않는 x=0또는 x=(미정).
Jonathan H

3

나는 다음과 같은 것을 실행하여 기본적인 논리를 할 수 있음을 발견했다.

A=true
B=true
if ($A && $B); then
    C=true
else
    C=false
fi
echo $C

6
하나 는 할 수 있지만 정말 나쁜 생각입니다. ( $A && $B )놀랍게도 비효율적 인 작업입니다-을 호출하여 하위 프로세스를 생성 한 fork()다음 내용을 문자열 분할하여 $A요소 목록 (이 경우 크기 1)을 생성하고 각 요소를 glob (이 경우 1)로 평가합니다 그 자체로 평가 된 다음 결과를 명령 (이 경우 내장 명령)으로 실행합니다.
Charles Duffy

3
또한 문자열 truefalse문자열이 다른 곳에서 나오는 경우 실제로 true또는 이외의 내용을 포함 false할 수 있으며 임의의 명령 실행까지 예기치 않은 동작이 발생할 수 있습니다.
Charles Duffy

6
그것은 많이있어 훨씬 안전은 쓰기 A=1; B=1if (( A && B ))- 숫자로 치료 - 나 [[ $A && $B ]], 어떤 취급 거짓 빈 문자열 참으로 비어 있지 않은 문자열입니다.
Charles Duffy

3
(나는 위의 all-caps 변수 이름 만 사용하여 대답에 의해 설정된 규칙을 따르고 있음을 유의하십시오-POSIX는 실제로 환경 변수와 쉘 내장에 사용되는 all-caps 이름을 명시 적으로 지정 하고 응용 프로그램 사용을 위해 소문자 이름을 예약합니다. 미래의 OS 환경과의 충돌을 피하기 위해, 특히 쉘 변수를 설정하면 비슷한 이름의 환경 변수를 덮어 쓰므로 항상 자체 스크립트에서 해당 규칙을 준수하는 것이 이상적입니다).
Charles Duffy

통찰력에 감사드립니다!
로드리고

2

true / false를 사용하면 일부 브라켓 클러 터가 제거됩니다 ...

#! /bin/bash    
#  true_or_false.bash

[ "$(basename $0)" == "bash" ] && sourced=true || sourced=false

$sourced && echo "SOURCED"
$sourced || echo "CALLED"

# Just an alternate way:
! $sourced  &&  echo "CALLED " ||  echo "SOURCED"

$sourced && return || exit

나는 이것이 도움이되었지만 우분투 18.04에서 $ 0은 "-bash"였고 basename 명령은 오류를 던졌습니다. 해당 테스트를 변경 [[ "$0" =~ "bash" ]] 하여 스크립트를 작동 시켰습니다.
WiringHarness 12
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.