변수 할당의 반환 상태는 어떻게 결정됩니까?


10

다음과 같은 스크립트에서 구문을 보았습니다.

if somevar="$(somecommand 2>/dev/null)"; then
...
fi

이것은 어딘가에 기록되어 있습니까? 변수의 반환 상태는 어떻게 결정되며 명령 대체와 어떤 관련이 있습니까? (예를 들어, if echo "$(somecommand 2>/dev/null)"; then? 와 동일한 결과를 얻을 수 있습니까?)

답변:


13

Open Group Base 사양의 섹션 2.9.1 간단한 명령 에 (POSIX 용) 문서화되어 있습니다. 거기에 텍스트 벽이 있습니다. 마지막 단락에주의를 기울입니다.

명령 이름이 있으면 명령 검색 및 실행에 설명 된대로 실행이 계속됩니다 . 명령 이름이 없지만 명령에 명령 대체가 포함 된 경우 명령은 마지막으로 수행 된 명령 대체의 종료 상태로 완료됩니다. 그렇지 않으면 명령은 종료 상태 0으로 완료됩니다.

예를 들어

   Command                                         Exit Status
$ FOO=BAR                                   0 (but see also the note from icarus, below)
$ FOO=$(bar)                                Exit status from "bar"
$ 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 = $ ( cmd 1 ) B = $ ( cmd 2 ) C = $ ( cmd 3 ) D = $ ( cmd 4 ) E = mc 2
의 종료 상태입니다 . 애프터 발생 할당 할당은 0으로 전반 종료 상태를 설정하지 않습니다.cmd4E=D=

루스는phk의 질문에 대한 그의 대답 , 중요한 점을 제기 변수는 읽기 전용으로 설정할 수 있습니다. 세 번째 - 투 - 마지막 단락 섹션 2.9.1는 POSIX 표준의 말한다

변수 할당이 읽기 전용 속성이 현재 쉘 환경에서 설정되어 있는 변수에 값을 할당하려고하면 (해당 환경에서 할당이 이루어 졌는지 여부에 관계없이) 변수 할당 오류가 발생합니다. 이러한 오류의 결과 는 셸 오류 의 결과를 참조하십시오 .

그래서 당신이 말하면

readonly A
C=Garfield A=Felix T=Tigger

반환 상태는 1입니다 그것은 중요하지 않습니다 경우, 문자열 Garfield, Felix및 / 또는 Tigger 명령 치환 (들)로 대체됩니다 -하지만 아래의 정보를 참조하십시오.

2.8.1 절 셸 오류의 결과 에는 다른 텍스트와 테이블이 있으며 다음으로 끝납니다.

대화식 쉘을 종료하지 않아도되는 표에 표시된 모든 경우에 쉘은 오류가 발생한 명령의 추가 처리를 수행하지 않아야합니다.

세부 사항 중 일부는 의미가 있습니다. 일부는하지 않습니다 :

  • A=할당은 때때로 중단 마지막 문장을 지정하는 것 같은 명령 줄을. 위의 예에서는 C로 설정 Garfield되었지만 T설정되지 않았습니다 (물론 둘 다 아닙니다  A).
  • 마찬가지로 실행 하지만 실행 하지는 않습니다 . 그러나 내 버전의 bash (4.1.X 및 4.3.X 포함) 에서는 실행 됩니다. (우연히, 이것은 과제의 종료 값이 과제의 오른쪽보다 먼저 적용된다는 phk의 해석을 더욱 심화시킵니다.)C=$(cmd1) A=$(cmd2) T=$(cmd3)cmd1cmd3
    cmd2

그러나 여기 놀람이 있습니다.

내 버전의 bash에서

읽기 전용 A
C = 무언가 A = 무언가 T = 무언가  cmd 0

않습니다 실행합니다. 특히,cmd0

C = $ ( cmd 1 ) A = $ ( cmd 2 ) T = $ ( cmd 3 )    cmd 0
및 실행 하지만 실행 하지는 않습니다 . (어떤 명령이없는 경우 참고이. 그 동작의 반대입니다) 그리고 설정 (물론로 의 환경에서) . 이것이 bash의 버그인지 궁금합니다.cmd1cmd3cmd2TCcmd0


그렇게 간단하지 않습니다.

이 답변의 첫 번째 단락은 "간단한 명령"을 나타냅니다.  사양에 따르면

"간단한 명령"은 제어 연산자에 의해 종료되는 임의의 순서로, 선택적인 변수 할당 및 재지향의 순서이며, 임의의 순서로 단어 및 재지향이 뒤 따른다.

다음은 첫 번째 예제 블록의 문장과 같은 문장입니다.

$ FOO=BAR
$ FOO=$(bar)
$ FOO=$(bar) baz
$ foo $(bar)

처음 세 개에는 변수 할당이 포함되고 마지막 세 개에는 명령 대체가 포함됩니다.

그러나 일부 변수 할당은 그렇게 간단하지 않습니다.  bash (1) 는 말합니다.

할당 문은 인수로 나타날 수 alias, declare, typeset, export, readonly, 및 local명령 (내장 선언 명령 등)을 선택합니다.

를 들어 export, POSIX의 사양은 말한다

종료 상태

    0
      모든 이름 피연산자가 내보내졌습니다.
    > 0
      하나 이상의 이름을 내보낼 수 없거나 -p옵션이 지정되어 오류가 발생했습니다.

POSIX는을 지원하지 local않지만 bash (1) 는 말합니다.

local함수 내에 있지 않을 때 사용하는 것은 오류 입니다. local함수 외부에서 사용 되거나 유효하지 않은 이름 이 제공되거나 name 이 읽기 전용 변수가 아닌 한 리턴 상태는 0 입니다.

행 사이를 읽으면 선언 명령이

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

운 좋게도 ShellCheck 는 오류를 포착하고 SC2155 를 발생 시킵니다 .

export foo="$(mycmd)"

로 변경되어야합니다

foo=$(mycmd)
export foo

local foo="$(mycmd)"

로 변경되어야합니다

local foo
foo=$(mycmd)

1
감사합니다! 보너스 포인트의 경우, local이것과 어떻게 연결되어 있는지 알고 있습니까? 예를 들어 local foo=$(bar)?
와일드 카드

1
두 번째 예 (단지 FOO=$(bar))의 경우 이론적으로 종료 상태 할당이 모두 역할을 수행 할 수 있다는 점에 주목할 필요가 있습니다. unix.stackexchange.com/a/341013/117599
phk

1
@Wildcard : 당신이 좋아서 기뻐요. 방금 다시 업데이트했습니다. 방금 읽은 버전의 큰 부분이 잘못되었습니다. 당신이 여기있는 한 어떻게 생각하세요? 이것은 bash의 버그 입니까, 읽기 전용 인 경우에도 A=foo cmd실행 됩니까? cmdA
G-Man은 'Reinstate Monica'라고 말합니다.

1
@ phk : (1) 재미있는 이론이지만 그것이 어떻게 이해되는지 잘 모르겠습니다. 나의“놀람”표제 직전의 예를 다시 살펴보십시오. 경우 A읽기 전용 명령 C=value₁ A=value₂ T=value₃세트 C하지만 T(그리고 물론, A설정되지 않은) - 쉘 무시 명령 행 처리 종결 된 T=value₃때문에 A=value₂에러이다. (2) Stack Overflow 질문 에 대한 링크에 감사드립니다 . 게시 한 의견이 있습니다.
G-Man, 'Reinstate

1
@Wildcard "보너스 포인트의 경우, 지역과의 관계를 알고 있습니까?" 예 ... 맨 페이지에서 다음과 같은 이유로 local=$(false)종료 값이 있습니다. 세상에 그런 식으로 디자인 한 천재에게는 트롤 페이스가 충분하지 않습니다. 0It is an error to use local when not within a function. The return status is 0 unless local is used outside a function, an invalid name is supplied, or name is a readonly variable.
David Tonhofer

2

Bash ( LESS=+/'^SIMPLE COMMAND EXPANSION' bash)에 문서화되어 있습니다 .

확장 후에 명령 이름이 남아있는 경우 .... 그렇지 않으면 명령이 종료됩니다. ... 명령 대체가없는 경우 명령은 상태 0으로 종료됩니다.

다른 말로하면 (내 말) :

확장 후 남아있는 명령 이름이없고 명령 대체가 실행되지 않은 경우 명령 행은 상태 0으로 종료됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.