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


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.