의사 결정 구조에 대해 배우고 있으며 다음 코드를 발견했습니다.
if [ -f ./myfile ]
then
cat ./myfile
else
cat /home/user/myfile
fi
[ -f ./myfile ] &&
cat ./myfile ||
cat /home/user/myfile
둘 다 동일하게 동작합니다. 한 가지 방법을 다른 방법으로 사용하면 어떤 이점이 있습니까?
의사 결정 구조에 대해 배우고 있으며 다음 코드를 발견했습니다.
if [ -f ./myfile ]
then
cat ./myfile
else
cat /home/user/myfile
fi
[ -f ./myfile ] &&
cat ./myfile ||
cat /home/user/myfile
둘 다 동일하게 동작합니다. 한 가지 방법을 다른 방법으로 사용하면 어떤 이점이 있습니까?
답변:
아니, 구조 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 A; then B; else C; fi
.
대부분의 사람들은 이해하기가 더 쉽습니다 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
. 먼저 a
실행됩니다. 이 경우 fails
한 후 그룹이 종료 상태 0, 반환하지로 정의 (a && b)
로 알려져을 fail
하고 b
실행할 필요가 없습니다. 는 ||
식의 결과가 그렇게 실행해야 알 수 없습니다 c
. 경우 a
성공 (0을 리턴) 다음 &&
의 연산자는 아직 결과를 모르는 a && b
그래서 실행해야 b
알아. 경우 b
다음 성공 a && b
성공하고는 ||
전체 결과를 알 수 있도록 실행에 필요하지 않습니다, 성공입니다 c
. 만약 b
에 실패||
여전히 표현식의 값을 알지 못하므로 실행해야합니다 c
.
&& 연산자 는 이전 명령이 성공적으로 실행 된 경우 다음 명령을 실행합니다 (반환 된 종료 코드 ($?) 0 = 논리 참).
형식 A && B || C
으로 명령 (또는 조건) A 가 평가되고 A 가 true (성공, 종료 코드 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
.
이것에 대한 많은 혼동은이 AND 및 OR 목록을 호출하는 bash 문서 때문일 수 있습니다 . 논리적으로 유사하지만 &&
및 ||
대괄호 안에 발견, 그들은 다르게 작동합니다.
일부 예는이 가장 잘 설명 할 수 있습니다 ...
참고 : 단일 및 이중 대괄호 (
[ ... ]
및[[ ... ]]
)는 자체적으로 명령을 비교하고 종료 코드를 반환하는 명령입니다. 그들은 실제로 필요하지 않습니다if
.
cmda && cmdb || cmdc
cmda
종료 하면 cmdb
실행됩니다. false로 종료
하면 실행되지 않지만 입니다.cmda
cmdb
cmdc
cmda; cmdb && cmdc || cmdd
cmda
종료가 무시되는 방법 종료
하면 실행됩니다. cmdb
cmdc
false로 종료
하면 실행되지 않고 입니다.cmdb
cmdc
cmdd
cmda && cmdb; cmdc
경우 cmda
진정한 종료가 cmdb
실행되고, 다음에 cmdc
. false로 종료
하면 실행 되지 않지만 입니다.cmda
cmdb
cmdc
응? 왜 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
}