스크립트에서 다음 구성을 본 적이 있습니다.
if somevar="$(somecommand 2>/dev/null)"; then
...
fi
이것이 어딘가에 문서화되어 있습니까? 변수의 반환 상태는 어떻게 결정되며 명령 대체와 어떤 관련이 있습니까? (예를 들어, 동일한 결과를 얻을 수 있습니까 if echo "$(somecommand 2>/dev/null)"; then
?)
답변1
문서화되어 있습니다 (POSIX의 경우)2.9.1 간단한 명령 그룹 기본 사양을 공개합니다. 거기에는 텍스트 벽이 있습니다. 마지막 단락에 주의를 기울이십시오.
명령 이름이 있으면 다음에 설명된 대로 실행을 계속해야 합니다.명령어 검색 및 실행. 명령 이름은 없지만 명령에 명령 대체가 포함된 경우 명령은 마지막으로 실행된 명령 대체의 종료 상태로 완료되어야 합니다. 그렇지 않으면 명령은 0 종료 상태로 완료되어야 합니다.
예를 들어,
Command Exit Status
$ FOO=BAR 0 (but see also the note from icarus, below)
$ FOO=$(bar) Exit status from "bar"
$ FOO=$(bar)$(quux) Exit status from "quux"
$ FOO=$(bar) baz Exit status from "baz"
$ foo $(bar) Exit status from "foo"
bash도 이런 식으로 작동합니다. 하지만 마지막에 있는 "그다지 단순하지 않음" 섹션도 참조하세요.
PHK, 그의 질문에할당은 명령 대체가 없는 한 종료 상태가 있는 명령과 같습니다.,제안
...할당 자체가 명령으로 간주되는 것 같습니다...종료 값은 0이지만 할당의 오른쪽 앞에 적용됩니다(예: 명령 대체 호출...)
그것은 문제를 보는 끔찍한 방법이 아닙니다. 간단한 명령( ;
, &
또는 |
제외 ) &&
의 반환 상태를 결정하는 대략적인 방식은 다음 ||
과 같습니다.
끝이나 명령 단어(보통 프로그램 이름)에 도달할 때까지 왼쪽에서 오른쪽으로 줄을 스캔합니다.
변수 할당이 표시되면 해당 줄의 반환 상태는 아마도 0일 것입니다.
명령 대체가 표시되면
$(…)
해당 명령의 종료 상태를 가져옵니다.실제 명령에 도달하면(명령 대체가 아님) 해당 명령의 종료 상태를 가져옵니다.
행의 반환 상태는 마지막으로 발생한 숫자입니다.
명령 대체매개변수로와 같은 명령의 경우foo $(bar)
종료 상태를 확인할 수 있습니다foo
. 의역phk 표기법, 여기서의 동작은 다음과 같습니다temporary_variable = EXECUTE( "bar" ) overall_exit_status = EXECUTE( "foo", temporary_variable )
그러나 이것은 좀 너무 단순하다. 전반적인 반품 상태는 다음에서 비롯됩니다.
A=$(명령 1) B=$(명령 2) C=$(명령 3) D=$(명령 4) E=MC 2종료 상태입니다. 할당 후에 발생하는 할당은 전체 종료 상태를 0으로 설정하지 않습니다.
cmd4
E=
D=
이카루스, 존재하다phk 질문에 대한 그의 대답, 중요한 점을 제시합니다. 변수는 읽기 전용으로 설정할 수 있습니다. 마지막 단락에서 세 번째POSIX 표준 섹션 2.9.1설명하다,
변수 할당이 해당 변수에 값을 할당하려고 시도하는 경우읽기 전용현재 쉘 환경에서 속성이 설정되면(해당 환경에서 할당되었는지 여부에 관계없이) 변수 할당 오류가 발생합니다. 바라보다쉘 오류의 결과이러한 실수의 결과에 대해.
그래서 당신이 말한다면
readonly A
C=Garfield A=Felix T=Tigger
Garfield
반환 상태는 1입니다. 문자열 Felix
및/또는 Tigger
명령 대체로 대체되는지 여부는 중요하지 않습니다. 하지만 아래 참고 사항을 참조하세요.
2.8.1 쉘 오류의 결과또 다른 텍스트 묶음과 표가 있고 다음으로 끝납니다.
대화형 셸을 종료하지 않아야 하는 표에 표시된 모든 경우에 셸은 오류가 발생한 명령을 더 이상 처리하지 않아야 합니다.
일부 세부 사항은 의미가 있지만 일부는 의미가 없습니다.
A=
가끔 숙제를 해요중단하다마지막 문장이 지정하는 것처럼 명령줄입니다. 위의 예에서 는 으로C
설정되었지만 설정되지는 않았습니다(물론 둘 다 설정되지 않았습니다 ).Garfield
T
A
- 다시 말하지만, 실행은 되지만 실행은 안 됩니다.
C=$(cmd1) A=$(cmd2) T=$(cmd3)
cmd1
cmd3
하지만,내 bash 버전(4.1.X 및 4.3.X 포함)에서는하다구현하다. (BTW, 이는 할당의 종료 값이 할당의 오른쪽 앞에 적용된다는 phk의 해석을 더욱 탄핵합니다.)cmd2
하지만 놀라운 점은 다음과 같습니다.
내 bash 버전에서는
읽기 전용 A C=무엇A=무엇시간 =무엇 명령 0
하다구현하다. 특히,cmd0
C=$(명령 1) A=$(명령 2) 티=$(명령 3) 명령 0실행하고 실행하지만 실행하지 않습니다. (이것은 명령이 없는 동작과 반대라는 점에 유의하십시오.) 그리고 의 환경에도 설정됩니다. 이것이 bash의 버그인지 궁금합니다.
cmd1
cmd3
cmd2
T
C
cmd0
그렇게 간단하지는 않습니다.
이 답변의 첫 번째 단락은 "간단한 명령"을 나타냅니다. 사양설명하다,
"간단한 명령"은 임의의 순서로 선택적인 변수 할당 및 리디렉션의 시퀀스이며 선택적으로 단어와 리디렉션이 뒤따르고 제어 연산자에 의해 종료됩니다.
이 명령문은 첫 번째 예제 블록의 명령문과 유사합니다.
$ FOO=BAR
$ FOO=$(bar)
$ FOO=$(bar) baz
$ foo $(bar)
처음 3개에는 변수 할당이 포함되고, 마지막 3개에는 명령 대체가 포함됩니다.
그러나 일부 변수 할당은 그렇게 간단하지 않습니다. 큰 타격(1)설명하다,
할당문은 매개변수로 나타날 수도 있습니다.
alias
,declare
,typeset
,export
,readonly
, 그리고local
내장 명령(선언주문하다).
을 위한 export
,POSIX 사양설명하다,
종료 상태
0
모든 이름 피연산자를 성공적으로 내보냈습니다.
>0하나 이상의 이름을 내보낼 수 없거나
-p
옵션이 지정되어 오류가 발생했습니다.
POSIX는 지원되지 local
않지만큰 타격(1)설명하다,
사용 중 오류가 발생했습니다.
local
함수 내부가 아닐 때. 반환 상태는 0이 아닌 이상 0입니다.local
함수 외부에서 사용됨, 유효하지 않음이름제공하거나이름읽기 전용 변수입니다.
줄 사이를 읽어보면 선언된 명령이 다음과 같은 것을 알 수 있습니다.
export FOO=$(bar)
그리고
local FOO=$(bar)
더 좋아
foo $(bar)
종료 상태를 무시하고 bar
기본 명령( export
, local
또는 )을 기반으로 foo
종료 상태를 제공하는 한 . 그래서 이런 이상한 현상이 나타납니다
Command Exit Status
$ FOO=$(bar) Exit status from "bar"
(unless FOO is readonly)
$ export FOO=$(bar) 0 (unless FOO is readonly,
or other error from “export”)
$ local FOO=$(bar) 0 (unless FOO is readonly,
statement is not in a function,
or other error from “local”)
우리는 그것을 증명하는 데 사용할 수 있습니다
$ export FRIDAY=$(date -d tomorrow)
$ echo "FRIDAY = $FRIDAY, status = $?"
FRIDAY = Fri, May 04, 2018 8:58:30 PM, status = 0
$ export SATURDAY=$(date -d "day after tomorrow")
date: invalid date ‘day after tomorrow’
$ echo "SATURDAY = $SATURDAY, status = $?"
SATURDAY = , status = 0
그리고
myfunc() {
local x=$(echo "Foo"; true); echo "x = $x -> $?"
local y=$(echo "Bar"; false); echo "y = $y -> $?"
echo -n "BUT! "
local z; z=$(echo "Baz"; false); echo "z = $z -> $?"
}
$ myfunc
x = Foo -> 0
y = Bar -> 0
BUT! z = Baz -> 1
다행스럽게도주택 검사오류를 잡아서 올려라SC2155, 이는 다음을 나타냅니다.
export foo="$(mycmd)"
로 변경해야합니다
foo=$(mycmd)
export foo
그리고
local foo="$(mycmd)"
로 변경해야합니다
local foo
foo=$(mycmd)
크레딧 및 참고자료
$(bar)$(quux)
Gilles의 답변에서 명령 대체를 연결하는 아이디어를 얻었습니다.
Pipefail과 비슷한 방식으로 백틱 실패 시 bash를 종료하려면 어떻게 해야 합니까?, 이 문제와 관련된 많은 정보가 포함되어 있습니다.
답변2
LESS=+/'^SIMPLE COMMAND EXPANSION' bash
Bash()에 문서화되어 있습니다.
확장 후에도 명령어 이름이 남아 있다면.... 그렇지 않으면 명령어가 종료됩니다. ...명령 대체 없이 명령은 상태 0으로 종료됩니다.
즉 (내 말은):
확장 후에 명령 이름이 남지 않고 명령 대체가 수행되지 않으면 명령줄은 0 상태로 종료됩니다.