의사결정 구조에 대해 배우고 있는데 다음 코드를 발견했습니다.
if [ -f ./myfile ]
then
cat ./myfile
else
cat /home/user/myfile
fi
[ -f ./myfile ] &&
cat ./myfile ||
cat /home/user/myfile
둘 다 같은 방식으로 행동합니다. 한 가지 방법을 다른 방법보다 사용하면 어떤 이점이 있습니까?
답변1
대부분의 사람들은 형식을 이해하는 것이 더 쉽다고 생각합니다 if
.then
else
fi
의 경우 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
성공 하고 전체 결과는 성공적인 것으로 알려져 있으므로 실행할 필요가 없습니다 . 실패하면 표현식 의 값을 아직 알 수 없으므로 실행해야 합니다 .b
a && b
||
c
b
||
c
답변2
아니요, 구조 if A; then B; else C; fi
는 A && 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...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 test
0.
./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
명령 및 의 종료 코드에 관계없이 모든 명령이 계속 실행됩니다.A
B
답변4
이에 대한 대부분의 혼란은 아마도 bash 문서에서 다음을 호출한다는 사실 때문일 것입니다.AND 및 OR 목록. 대괄호 안의 대괄호 &&
와 논리적으로 유사하지만 ||
기능은 다릅니다.
몇 가지 예가 이를 가장 잘 설명합니다.
참고: 단일 및 이중 대괄호(
[ ... ]
및[[ ... ]]
) 자체는 비교를 수행하고 종료 코드를 반환하는 명령입니다. 그들은 실제로 그럴 필요가 없습니다if
.
cmda && cmdb || cmdc
cmda
true로 종료 되면 cmdb
실행됩니다.
cmda
종료가 false 이면 cmdb
실행되지 않고 cmdc
실행됩니다.
cmda; cmdb && cmdc || cmdd
종료 방법은 cmda
무시됩니다.
cmdb
true로 종료 되면 cmdc
실행됩니다.
cmdb
종료가 false이면 실행 cmdc
되지 않고 cmdd
실행됩니다.
cmda && cmdb; cmdc
cmda
true로 종료 되면 cmdb
실행한 다음 실행합니다 cmdc
.
종료 가 cmda
거짓이면 cmdb
실행하지 않음하지만 cmdc
.
아? 그는 왜 cmdc
처형되었나요?
인터프리터에게는 세미콜론( ;
)과 개행 문자가 정확히 같은 의미를 갖기 때문입니다. Bash는 이 코드 줄을 다음과 같이 취급합니다.
cmda && cmdb
cmdc
cmdb; cmdc
원하는 효과를 얻으려면 중괄호로 묶어야 합니다.복합명령(그룹명령). 추가 종료 세미콜론은 { ...; }
구문 요구 사항일 뿐입니다. 그래서 우리는 ...
cmda && { cmdb; cmdc; }
cmda
true로 종료 되면 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
}