고쳐 쓰다:

고쳐 쓰다:

zsh스크립트에는 긴 명령 파이프라인이 있습니다.

pv /dev/sda > sda.raw | sha256sum > sda.raw.sha256 | cut -c61-64 | read SHASUM

if모든 명령이 성공적으로 종료되었는지 문 내부에서 어떻게 확인할 수 있나요 ?

알아요 ${pipestatus[@]}. 하지만 배열이에요. 그래서 각 요소를 개별적으로 확인해야 합니다.

${pipestatus[@]}포함된 내용만 확인하는 바로가기가 있습니까 0?

고쳐 쓰다:

몇 가지 이상한 동작을 발견했습니다.

테스트를 위해 빠르게 채워지도록 작은 파일 시스템(10MB)을 설정했습니다.

#!/bin/zsh

set -o pipefail

if pv /dev/zero > loop/file ; then
echo OK
else
echo FAIL
fi

예상대로 "FAIL"을 인쇄하면서 다음 오류가 발생합니다.

pv: write failed: No space left on device

그런데 pv 명령을 약간 변경하면 갑자기 오류가 인쇄되지 않고 pv 명령이 무한정 실행되는 것처럼 보입니다(장치에 남은 공간이 없음에도 불구하고).

#!/bin/zsh

set -o pipefail

if pv /dev/zero > loop/file | sha256sum ; then
echo OK
else
echo FAIL
fi

답변1

두 가지 옵션:

  1. pipefail이 옵션이 ksh() 에서 설정되면 set -o pipefail파이프라인의 종료 상태는 가장 오른쪽에 실패한 파이프라인 구성 요소의 종료 상태가 됩니다.

    set -o pipefail
    if ! A | B | C; then
      echo at least one of the commands failed.
    fi
    
  2. 검색에서 0이 아닌 값을 찾습니다 $pipestatus. 이 extendedglob옵션을 활성화 하면 가장 왼쪽의 실패한 파이프라인 구성 요소와 가장 오른쪽의 실패한 파이프라인 구성 요소 의 종료 상태가 반환되므로 $pipestatus[(r)^0](또는 $pipestatus[(r)<1->]not 필수 ) 다음을 수행할 수 있습니다.extendedglob$pipestatus[(R)^0]

    set -o extendedglob
    A | B | C
    if (( $pipestatus[(r)^0] )); then
      echo at least one of the commands failed.
    fi
    

    또는

    A | B | C
    if (( $pipestatus[(r)<1->] )); then
      echo at least one of the commands failed.
    fi
    

    / I대신 아래 첨자 플래그를 사용하면 가장 오른쪽에 일치하는 요소의 인덱스를 얻을 수 있으므로 다음을 수행할 수 있습니다.rRI

    A | B | C
    if (( failed = $pipestatus[(I)<1->] )); then
      echo component $failed failed.
    fi
    

    ${pipestatus:#0}0 이외의 구성 요소로 확장되므로 다음을 $pipestatus수행할 수도 있습니다.

    A | B | C
    failed_statuses=( ${pipestatus:#0} )
    if (( $#failed_statuses )); then
      echo "${#failed_statuses} command(s) failed. Statuses: $failed_statuses"
    fi
    

관련 정보