if else 문은 논리 및 && 또는 || 어떤 면에서 다른 것보다 선호해야 합니까?

if else 문은 논리 및 && 또는 || 어떤 면에서 다른 것보다 선호해야 합니까?

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

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


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

둘 다 같은 방식으로 행동합니다. 한 가지 방법을 다른 방법보다 사용하면 어떤 이점이 있습니까?

답변1

대부분의 사람들은 형식을 이해하는 것이 더 쉽다고 생각합니다 if.thenelsefi

의 경우 true가 반환되는지 a && b || c확인해야 합니다 . b이는 미묘한 오류의 원인이며 이 스타일을 피해야 하는 좋은 이유입니다.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. 종료 상태 0을 반환하지 않도록 정의된 a경우 fails그룹이 (a && b)알려진 fail것이므로 b실행할 필요가 없습니다. 표현식의 결과를 알 수 없으므로 ||실행이 필요합니다 c. 성공 하면 a(0을 반환) &&연산자는 아직 결과를 알 수 없으며 알아내기 위해 a && b실행해야 합니다 . 성공하면 b성공 하고 전체 결과는 성공적인 것으로 알려져 있으므로 실행할 필요가 없습니다 . 실패하면 표현식 의 값을 아직 알 수 없으므로 실행해야 합니다 .ba && b||cb||c

답변2

아니요, 구조 if A; then B; else C; fiA && B || C그렇습니다.같지 않음.

를 사용하면 if A; then B; else C; fi명령은 항상 평가되고 실행됩니다 A(적어도 실행을 시도한 경우). 그런 다음 명령 B이나 명령이 평가되고 실행됩니다.C

A && B || C명령의 경우에는 동일 A하지만 다릅니다. 다음과 같은 경우 B명령이 평가되고 실행됩니다 .CC누구나 A실패하다또는 B실패하다.

귀하의 예에서 귀하를 가정하면 성공 chmod u-r ./myfile에도 불구하고[ -f ./myfile ]cat /home/user/myfile

내 조언: 읽고 이해하기 쉽고 문제가 없는 원하는 것을 사용하거나 A && B사용하세요 . A || B하지만 if...then...else...then을 의미한다면 를 사용하세요 if A; then B; else C; fi.

답변3

운영자&&이전 명령이 성공적으로 실행되면 다음 명령을 실행합니다(종료 코드($?) 0 = 논리적 true 반환).

양식 A && B || C, 명령(또는 조건)평가되고 만약반품진짜(성공, 종료 코드 0) 다음 명령두번째처형되다. 만약에실패(그래서 반환됩니다)잘못된- 0이 아닌 종료 코드) 및/또는두번째실패(반품잘못된) 그런 다음 명령실행됩니다.

연산자는 다음과 &&같이 사용됩니다.그리고조건 확인 및 연산자는 ||다음과 같이 작동합니다.또는상태 확인중입니다.

스크립트로 수행하려는 작업에 따라 양식을 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
echo "Something"이 섹션은 성공하고 작업이 종료 코드를 반환하는 경우에만 실행 됩니다.mkdir test0.

./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그렇지 않은 경우). 이러한 명령은 주의해서 다루어야 합니다.&&그리고||.

또한, 퍼즐의 모든 조각을 하나로 맞추려면 연산자를 사용하여 명령을 연결하는 데 주의하세요 ;. 형식을 사용하면 A;B;C명령 및 의 종료 코드에 관계없이 모든 명령이 계속 실행됩니다.AB

답변4

이에 대한 대부분의 혼란은 아마도 bash 문서에서 다음을 호출한다는 사실 때문일 것입니다.AND 및 OR 목록. 대괄호 안의 대괄호 &&와 논리적으로 유사하지만 ||기능은 다릅니다.

몇 가지 예가 이를 가장 잘 설명합니다.

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

cmda  && cmdb  || cmdc

cmdatrue로 종료 되면 cmdb실행됩니다.
cmda종료가 false 이면 cmdb실행되지 않고 cmdc실행됩니다.

cmda; cmdb  && cmdc  || cmdd

종료 방법은 cmda무시됩니다.
cmdbtrue로 종료 되면 cmdc실행됩니다.
cmdb종료가 false이면 실행 cmdc되지 않고 cmdd실행됩니다.

cmda  && cmdb; cmdc

cmdatrue로 종료 되면 cmdb실행한 다음 실행합니다 cmdc.
종료 가 cmda거짓이면 cmdb실행하지 않음하지만 cmdc.

아? 그는 왜 cmdc처형되었나요?
인터프리터에게는 세미콜론( ;)과 개행 문자가 정확히 같은 의미를 갖기 때문입니다. Bash는 이 코드 줄을 다음과 같이 취급합니다.

cmda  && cmdb
cmdc  

cmdb; cmdc원하는 효과를 얻으려면 중괄호로 묶어야 합니다.복합명령(그룹명령). 추가 종료 세미콜론은 { ...; }구문 요구 사항일 뿐입니다. 그래서 우리는 ...

cmda && { cmdb; cmdc; }
cmdatrue로 종료 되면 cmdb실행한 다음 실행합니다 cmdc.
cmda종료가 false 이면 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
}

관련 정보