파이프라인에서 최종이 아닌 명령의 종료 상태를 어떻게 캡처합니까?

파이프라인에서 최종이 아닌 명령의 종료 상태를 어떻게 캡처합니까?

파이프라인 어딘가에서 발생하는 명령의 종료 상태를 캡처하고 싶습니다.~ 전에마지막 위치. 예를 들어 파이프라인이 다음과 같은 경우

command_1 ... | command_2 ... | command_3 ... | ... | command_n

command_1... , 또는 command_2, 또는 등 의 종료 상태를 캡처하는 방법을 알고 싶습니다. ( 물론 command_3의 종료 상태를 캡처하는 것은 쉽지 않습니다.)command_n

또한 중요한 경우 이 파이프라인은 zsh 쉘 기능 내에서 발생합니다.


command_1나는 다음과 같은 종료 상태를 포착하려고 시도했습니다.

function_with_pipeline () {

    local command_1_status=-999999  # sentinel value

    { command_1 ...; command_1_status=$? } | command_2 ... | ... | command_n
    ...

}

...하지만 파이프라인을 실행한 후에도 변수 값은 command_1_status여전히 ​​센티널 값이었습니다.


FWIW, 다음은 파이프라인에 두 개의 명령만 있는 작업 예제입니다.

foo ... | grep ...

foo이 예를 위해 다음과 같이 정의된 함수입니다.

foo () {

    (( $1 & 1 )) && echo "a non-neglible message"
    (( $1 & 2 )) && echo "a negligible message"
    (( $1 & 4 )) && echo "error message" >&2

    return $(( ( $1 & 4 ) >> 2 ))
}

foo목표는 파이프라인에서 호출의 종료 상태를 캡처하는 것입니다 .

이 함수는 function_with_pipeline이를 수행하기 위해 위에서 설명한 (궁극적으로 비효율적인) 전략을 구현합니다.

function_with_pipeline () {

    local foo_status=-999999  # sentinel value

    { foo $1; foo_status=$? } | grep -v "a negligible message"

    printf '%d\ndesired: %d; actual: %d\n\n' $1 $(( ( $1 & 4 ) >> 2 )) $foo_status

}

아래 루프는 function_with_pipeline기능을 실행합니다. 출력은 지역 변수의 값이 foo_status시작된 방식과 다르지 않게 끝나는 것을 보여줍니다.

for i in $(seq 0 7)
do
    function_with_pipeline $i
done
# 0
# desired: 0; actual: -999999
# 
# a non-neglible message
# 1
# desired: 0; actual: -999999
# 
# 2
# desired: 0; actual: -999999
# 
# a non-neglible message
# 3
# desired: 0; actual: -999999
# 
# error message
# 4
# desired: 1; actual: -999999
# 
# error message
# a non-neglible message
# 5
# desired: 1; actual: -999999
# 
# error message
# 6
# desired: 1; actual: -999999
# 
# error message
# a non-neglible message
# 7
# desired: 1; actual: -999999
#

local의 정의에서 선언을 생략해도 동일한 결과를 얻습니다 foo_status.

답변1

pipestatus에는 이에 대한 특별한 배열이 있으므로 zsh시도해 보십시오.

command_1 ... | command_2 ... | command_3

그리고

echo $pipestatus[1] $pipestatus[2] $pipestatus[3]

귀하의 접근 방식이 작동하지 않는 이유는 각 파이프가 별도의 하위 쉘에서 실행되고 하위 쉘을 종료하면 자체 변수가 파괴되기 때문입니다.


참고로 는 PIPESTATUS(대문자로) 입니다 bash.

답변2

mispipe모든 쉘에서 작동합니다. 일반 파이프와 비교하여 구문은 다음과 같이 작동합니다.

mispipe true false ; echo $?  # returns exit code of 1st command `true`
true | false ; echo $?  # returns exit code of 2nd command `false`

산출:

0
1

두 개 이상의 프로그램이 있는 경우 수행할 작업:

# this still returns exit code of 1st command `true`
mispipe true 'false | false | false' ; echo $?

산출:

0

visible 이 부족함에도 불구하고 |여전히 파이프처럼 작동합니다.

yes | mispipe head 'wc -c'

산출:

     20

관련 정보