[unix] 부울 변수 반전

간단한 스크립트를 사용하고 싶습니다

flag=false
while !$flag
do
   read x
   if [ "$x" -eq "true" ]
   then
     flag=true
   fi
   echo "${x} : ${flag}"
done

그러나 그것을 실행할 때을 입력 true하면 x="true"및 을 볼 수 flag="true"있지만주기는 끝나지 않습니다. 스크립트에 어떤 문제가 있습니까? 부울 변수를 올바르게 반전시키는 방법은 무엇입니까?



답변

스크립트에 두 가지 오류가 있습니다. 첫 번째는 당신이 사이의 공간이 필요하다 !$flag라는 명령, 그렇지 않으면 쉘 모습을 !$flag. 두 번째 오류는 -eq정수 비교에 관한 것이지만 문자열에서 사용하고 있습니다. 쉘에 따라 오류 메시지가 표시되고 조건을 충족 [ "$x" -eq "true" ]할 수 없기 때문에 루프가 계속 지속 되거나 정수가 아닌 모든 값은 0으로 처리되며 문자열을 입력하면 루프가 종료됩니다 (포함 false) 0과 다른 숫자 이외의

하지만 ! $flag올바른, 그것은 명령으로 문자열을 처리하는 나쁜 생각입니다. 그것은 작동,하지만 당신이 있는지 확인해야 할 것입니다 이후는, 스크립트의 변화에 매우 민감 것 $flag아무것도하지만, 결코 수 있습니다 true또는 false. 아래 테스트와 같이 여기에서 문자열 비교를 사용하는 것이 좋습니다.

flag=false
while [ "$flag" != "true" ]
do
   read x
   if [ "$x" = "true" ]
   then
     flag=true
   fi
   echo "${x} : ${flag}"
done

당신이 따르는 논리를 표현하는 더 좋은 방법이있을 것입니다. 예를 들어, 종료 조건을 감지하면 무한 루프를 만들고 끊을 수 있습니다.

while true; do
  read -r x
  if [ "$x" = "true" ]; then break; fi
  echo "$x: false"
done


답변

Bash에는 부울 변수가 없지만 산술 평가를 사용하여 쉽게 부울 변수를 에뮬레이션 할 수 있습니다.

flag= # False
flag=0 # False
flag=1 # True (actually any integer number != 0 will do, but see remark below about toggling)
flag="some string" # Maybe False (make sure that the string isn't interpreted as a number)

if ((flag)) # Test for True
then
  : # do something
fi

if ! ((flag)) # Test for False
then
  : # do something
fi

flag=$((1-flag)) # Toggle flag (only works when flag is either empty or unset, 0, 1, or a string which doesn't represent a number)

이것은 ksh에서도 작동합니다. 모든 POSIX 호환 쉘에서 작동하더라도 놀라지 않지만 표준을 확인하지는 않았습니다.


답변

변수에 0 또는 1이 포함될 것을 확실히 확신 할 수 있으면 비트 XOR- 등호 연산자를 사용하여 두 값 사이를 전환 할 수 있습니다.

$ foo=0
$ echo $foo
0
$ ((foo ^= 1))
$ echo $foo
1
$ ((foo ^= 1))
$echo $foo
0


답변

이것은 나를 위해 작동합니다 :

flag=false
while [[ "$flag" == "false" ]]
do
   read x
   if [[ "$x" == "true" ]]
   then
     flag=true
   fi
   echo "${x} : ${flag}"
done

그러나 실제로, 당신이해야 할 일은 다음으로 대체하는 것 while입니다.

while ! $flag


답변

셸에는 부울 변수 개념이 없습니다.
쉘 변수는 될 수있는 text경우에, 그 텍스트 (정수로 해석 할 수있다, (AN 문자열), 및 1, 0xa, 010, 등).

따라서 flag=true셸에 대한 진실성 또는 거짓이 전혀 없음을 의미합니다.

수행 할 수있는 것은 문자열 비교 [ "$flag" == "true" ]또는 일부 명령에서 변수 내용을 사용 하고 결과 와 같은 결과를 확인 하고 실행하십시오 true(실행 파일 true과 호출 파일이 모두 있기 때문에 false) 명령으로 종료 명령이 0인지 확인하십시오 (성공한).

$flag; if [ "$?" -eq 0 ]; then ... fi

또는 더 짧게 :

if "$flag"; then ... fi

변수의 내용이 명령 !으로 사용 ! cmd되면 다음과 같이 ( ) 사이에 공백이 있으면 a를 사용하여 명령 의 종료 상태를 무효화 할 수 있습니다 .

if ! "$flag"; then ... fi

스크립트는 다음과 같이 변경되어야합니다.

flag=false
while ! "$flag"
do
   read x
   if [ "$x" == "true" ]
   then
     flag=true
   fi
   echo "${x} : ${flag}"
done

정수

숫자 값과 산술 확장을 사용하십시오 .

이 경우 종료 코드는 $((0))is 1이고 종료 코드는 $((1))입니다 0.
bash, ksh 및 zsh에서 산술은 내부에서 수행 될 수 있습니다 ((..))(시작 $이 누락 되었음을 유의하십시오 ).

flag=0; if ((flag)); then ... fi

이 코드의 이식 가능한 버전은 더 복잡합니다.

flag=0; if [ "$((flag))" -eq 0 ]; then ... fi      # test for a number
flag=0; if [ "$((flag))"  == 0 ]; then ... fi      # test for the string "0"

bash / ksh / zsh에서 다음을 수행 할 수 있습니다.

flag=0
while ((!flag))
do
   read x
   [ "$x" == "true" ] && flag=1
   echo "${x} : ${flag}"
done

대안 적으로

다음과 같이 “부울 변수 반전”(숫자 값이 포함 된 경우) :

((flag=!flag))

즉 것이다 변경 의 값 flag에 하나 0또는 1.


참고 : 코드를 질문으로 게시하기 전에 https://www.shellcheck.net/ 에서 오류를 확인 하십시오 . 여러 번 문제를 찾기에 충분합니다.


답변

until는 짧고 while !( Bourne until과 반대로 !) 다음을 수행 할 수 있습니다.

flag=false
until "$flag"
do
   IFS= read -r x
   if [ "$x" = true ]
   then
     flag=true
   fi
   printf '%s\n' "$x : $flag"
done

다음과 동일해야합니다.

flag=false
while ! "$flag"
do
   IFS= read -r x
   if [ "$x" = true ]
   then
     flag=true
   fi
   printf '%s\n' "$x : $flag"
done

다음과 같이 쓸 수도 있습니다.

until
   IFS= read -r x
   printf '%s\n' "$x"
   [ "$x" = true ]
do
   continue
done

until/ 사이 whiledo단일 명령 일 필요는 없습니다.

!POSIX 쉘 구문의 키워드입니다. 그것은 구분되어야하고, 다음에 나오는 것과 분리 된 토큰이어야하고 파이프 라인 앞에 오는 첫 번째 토큰이어야합니다 ( ! foo | bar파이프 라인을 foo | ! bar무효화하고 일부 쉘이이를 확장으로 허용하더라도 유효하지 않습니다).

!true!true존재하지 않는 명령 으로 해석됩니다 . ! true작동해야합니다. !(true)그 같이 POSIX 호환 쉘에서 작동해야 !그것이 다음 것으로 구분되어 (토큰 있지만, 실제로는에 일을하지 않는 ksh/ bash -O extglob그것은과 충돌 곳 !(pattern)이 충돌하는 곳 (SH 에뮬레이션 제외) 확장 글로브 운영자 나 zsh을 glob(qualifiers)가진 bareglobqualglob(group)없이.


답변

[ ${FOO:-0} == 0 ] && FOO=1 || FOO=0

또는:

[ ${FOO:-false} == false ] && FOO=true || FOO=false

일을해야한다