논리적이고 && 또는 || 어디에서 다른 것을 선호해야합니까?


27

의사 결정 구조에 대해 배우고 있으며 다음 코드를 발견했습니다.

if [ -f ./myfile ]
then
     cat ./myfile
else
     cat /home/user/myfile
fi


[ -f ./myfile ] &&
cat ./myfile ||
cat /home/user/myfile

둘 다 동일하게 동작합니다. 한 가지 방법을 다른 방법으로 사용하면 어떤 이점이 있습니까?



3
그것들 동등 하지 않습니다 . 이카루스의 탁월한 답변을보십시오. 예를 들어, ./myfile이 존재하지만 읽을 수없는 경우를 고려하십시오.
AlexP


답변:


26

아니, 구조 if A; then B; else C; fiA && B || C있습니다 동일하지 .

을 사용 if A; then B; else C; fi하면 명령 A이 항상 평가되고 실행되고 (적어도 실행 시도가 수행됨) 명령 B또는 명령 C이 평가 및 실행됩니다.

를 사용하면 A && B || C명령 A과 동일 B하지만 다음과 다릅니다 C.C 경우, 평가 및 실행 중 하나가 A 실패 하거나 B 실패합니다.

당신의 예에서 , 당신이 성공했다고 chmod u-r ./myfile하더라도 [ -f ./myfile ], 당신은cat /home/user/myfile

내 조언 : 사용 A && B또는A || B 원하는 모든 것, 이것은 읽고 이해하기 쉬우 며 함정이 없습니다. 그러나 만약 그렇다면 ... 그렇다면 ... 그렇다면 ...을 사용하십시오 if A; then B; else C; fi.


29

대부분의 사람들은 이해하기가 더 쉽습니다 if...then ... else... fi형식 .

의 경우 true a && b || cb반환 해야 합니다. 이것은 미묘한 버그의 원인이며이 스타일을 피하는 좋은 이유입니다.b가 true를 반환하지 않으면 동일하지 않습니다.

 $ if true; then false ; else echo boom ; fi
 $ true && false || echo boom
 boom

else 절이없는 매우 짧은 테스트 및 작업의 경우 단축 된 길이가 매력적입니다.

 die(){ printf "%s: %s\n" "$0" "$*" >&2 ; exit 1; }

 [ "$#" -eq 2] || die "Needs 2 arguments, input and output"

 if [ "$#" -ne 2 ] ; then
     die "Needs 2 arguments, input and output"
 fi

&&하고 ||있는 short circuiting operators즉시 결과는 공지 된 바와 같이 상기 불필요한 검사를 스킵있다. a && b || c로 그룹화됩니다 (a && b) || c. 먼저 a실행됩니다. 이 경우 fails한 후 그룹이 종료 상태 0, 반환하지로 정의 (a && b)로 알려져을 fail하고 b실행할 필요가 없습니다. 는 ||식의 결과가 그렇게 실행해야 알 수 없습니다 c. 경우 a성공 (0을 리턴) 다음 &&의 연산자는 아직 결과를 모르는 a && b그래서 실행해야 b알아. 경우 b다음 성공 a && b성공하고는 ||전체 결과를 알 수 있도록 실행에 필요하지 않습니다, 성공입니다 c. 만약 b에 실패||여전히 표현식의 값을 알지 못하므로 실행해야합니다 c.


7

&& 연산자 는 이전 명령이 성공적으로 실행 된 경우 다음 명령을 실행합니다 (반환 된 종료 코드 ($?) 0 = 논리 참).

형식 A && B || C으로 명령 (또는 조건) A 가 평가되고 Atrue (성공, 종료 코드 0)를 반환 하면 명령 B 가 실행됩니다. 경우 A가 실패하는 (따라서 반환합니다 거짓 - 종료 0이 아닌 코드) 및 / 또는 B가 실패 (반환 거짓 ) 다음 명령 C가 실행됩니다.

또한 &&연산자는 조건 검사에서 AND 로 사용되며 연산자는 조건 검사 에서 OR|| 처럼 작동 합니다.

스크립트로 수행하려는 작업에 따라 양식 A && B || C을 예제와 같은 조건 확인에 사용하거나 명령을 체인화하고 이전 명령에 종료 코드 0 이 성공적으로 수행 된 경우 일련의 명령을 실행하는 데 사용할 수 있습니다 .
이것이 다음과 같은 명령을 보는 것이 일반적인 이유
do_something && do_something_else_that_depended_on_something입니다.

예 :
apt-get update && apt-get upgrade 업데이트가 실패하면 업그레이드가 실행되지 않습니다 (실제로 이해가됩니다 ...).

mkdir test && echo "Something" > test/file
부품 이 성공하고 작업이 종료 코드 0을 반환 한 echo "Something"경우에만 부품 이 실행됩니다 . mkdir test

./configure --prefix=/usr && make && sudo make install
일반적으로 필요한 종속 명령을 함께 연결하기 위해 작업을 컴파일 할 때 발견됩니다.

당신과 함께 "체인"위에 구현하려고하면 경우 - 다음 - 다른 간단한 작업 - (잘못을 이동하기 위해 더 많은 일 때문에 더 많은 코드 쓰기에) 당신이 더 많은 명령과 검사가 필요합니다.

또한 &&||를 사용하여 연결 명령을 쉘은 왼쪽에서 오른쪽으로 읽습니다. 일부 이전 명령의 성공적인 출력에 따라 다음 단계에 따라 명령 및 조건 확인을 대괄호로 그룹화해야 할 수도 있습니다. 예를 들어 이것을보십시오 :

root@debian:$ true || true && false;echo $?
1 
#read from left to right
#true OR true=true AND false = false = exit code 1=not success

root@debian:$ true || (true && false);echo $?
0 
# true OR (true AND false)=true OR false = true = exit code 0 = success

또는 실제 예 :

root@debian:$ a=1;b=1;c=1;[[ $a -eq 1 ]] || [[ $b -eq 1 ]] && [[ $c -eq 2 ]];echo $?
1 
#condition $a = true OR condition b = true AND condition $c = false
#=> yields false as read from left to right, thus exit code=1 = not ok

root@debian:$ a=1;b=1;c=1;[[ $a -eq 1 ]] || [[ $b -eq 1 && $c -eq 2 ]];echo $?
0 
#vars b and c are checked in a group which returns false, 
#condition check of var a returns true, thus true OR false yields true = exit code 0

일부 명령은 실행 된 프로세스에 따라 다른 종료 코드를 반환하거나 작업에 따라 다른 코드를 반환합니다 (예 : 명령 GNU diff는 두 파일이 다르면 1을 , 그렇지 않으면 0을 반환 함). 이러한 명령은 &&|| 에서주의해서 다루어야합니다. .

또한 모든 퍼즐을 모으려면 ;operator를 사용하여 명령을 연결하십시오 . 형식을 사용하면 A;B;C명령 A및 의 종료 코드가 무엇이든 모든 명령이 직렬로 실행됩니다 B.


1

이것에 대한 많은 혼동은이 AND 및 OR 목록을 호출하는 bash 문서 때문일 수 있습니다 . 논리적으로 유사하지만 &&||대괄호 안에 발견, 그들은 다르게 작동합니다.

일부 예는이 가장 잘 설명 할 수 있습니다 ...

참고 : 단일 및 이중 대괄호 ( [ ... ][[ ... ]])는 자체적으로 명령을 비교하고 종료 코드를 반환하는 명령입니다. 그들은 실제로 필요하지 않습니다 if.

cmda  && cmdb  || cmdc

cmda종료 하면 cmdb실행됩니다. false로 종료
하면 실행되지 않지만 입니다.cmdacmdbcmdc

cmda; cmdb  && cmdc  || cmdd

cmda종료가 무시되는 방법 종료
하면 실행됩니다. cmdbcmdcfalse로 종료
하면 실행되지 않고 입니다.cmdbcmdccmdd

cmda  && cmdb; cmdc

경우 cmda진정한 종료가 cmdb실행되고, 다음에 cmdc. false로 종료
하면 실행 되지 않지만 입니다.cmdacmdbcmdc

응? 왜 cmdc처형됩니까?
인터프리터에게 세미콜론 ( ;)과 줄 바꿈은 정확히 같은 의미입니다. Bash는 코드 줄을 다음과 같이 봅니다.

cmda  && cmdb
cmdc  

예상되는 것을 달성하기 위해 cmdb; cmdc중괄호 안에 묶어 복합 명령 (그룹 명령) 으로 만들어야합니다 . 추가 종료 세미콜론은 { ...; }구문 의 요구 사항 일뿐 입니다. 그래서 우리는 ...

cmda && { cmdb; cmdc; }
경우 cmda진정한 종료가 cmdb실행되고, 다음에 cmdc.
경우 cmda종료의 거짓이 아니 cmdb거나 cmdc실행됩니다.
다음 줄부터 실행이 계속됩니다.

용법

조건부 명령 목록은 함수에서 가능한 빨리 반환하여 많은 불필요한 코드를 해석하고 실행하는 것을 피하는 데 가장 유용합니다. 그러나 여러 함수 반환은 가능한 모든 조건이 적용되는지 쉽게 알 수 있도록 함수를 짧게 유지하는 것에 강박 관념을 의미합니다.

다음은 실행중인 코드의 예입니다 ...

fnInit () {
  :
  _fn="$1"
  ### fnInit "${FUNCNAME}" ...
  ### first argument MUST be name of the calling function
  #
  [[ "$2" == "--help-all" ]]  && { helpAll                      ; return 0; }
  ### pick from list of functions
  #
  [[ "$2" == "--note-all" ]]  && { noteAll                      ; return 0; }
  ### pick from notes in METAFILE
  #
  [[ "$2" == "--version"  ]]  && { versionShow "${_fn}" "${@:3}"; return 0; }
  #
  [[ "$2" == "--function" ]]  && {
    isFnLoaded "$3"           && { "${@:3}"                     ; return 0; }
    #
    errorShow functionnotfound "Unknown function:  $3"
    return 0
  }
  ### call any loaded function
  #
  [[ "$2" == "--help" || "$2" == "-h" ]]  && { noteShow "$_fn" "${@:3}"; return 0; }
  ### fnInit "${FUNCNAME}" --help or -h
  #
  return 1
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.