파이프라인의 첫 번째 명령이 실패할 때 set -o 파이프라인실패를 강제하는 방법

파이프라인의 첫 번째 명령이 실패할 때 set -o 파이프라인실패를 강제하는 방법

Postgres 데이터베이스의 데이터를 Bash의 파일로 내보내려고 합니다. 하지만 데이터베이스 연결이 실패하지 않는 경우에만 파일을 덮어쓰고 싶습니다(예: 일부 데이터를 돌려받음).

사용해 보세요파이프 고장옵션이지만 첫 번째 명령이 오류로 인해 실패하면(예: 호스트가 존재하지 않음) cat 명령이 계속 실행되어 빈 파일을 생성합니다(방지하려는 마지막 좋은 항목을 지움). 다음 예에서 myhost는 잘못된 호스트이므로 psql 명령이 실패합니다.

따라서 더 큰 질문은 파이프 실패가 설정되었을 때 첫 번째 명령이 실패하면 후속 명령이 실행되지 않도록 하는 방법입니다.

#!/bin/sh
set -o nounset
set -o errexit
set -o pipefail

PG_HOST=myhost

psql $PG_HOST -At -F$'\t' -c "SELECT * FROM mytable" | cat > /tmp/mytable.txt

답변1

set -o pipefail -o errexit후속 명령이 실행되는 것을 방지하지만 방지하려고 하지 않기 때문에 도움이 되지 않습니다.후속명령이 실행됩니다. 파이프라인에서 producer | consumer실행 producerconsumer명령평행하게. 실패하면 비정상적인 타이밍 사고가 없는 한 이미 시작되었으므로 consumer시작을 막을 수 없습니다 .producer

두 가지 가능성만 " consumer성공하고 null이 아닌 출력 생성"과 " consumer실패하고 출력 없음 생성"인 경우 다음을 사용할 수 있습니다.ifneJoey Hess의 moreutils.

producer | ifne consumer

나는 이것이 귀하의 사용 사례에서 작동하지 않을 것이라고 생각합니다. 일치하는 행이 없을 수도 있고(긍정 오류, 오래된 데이터를 얻음) 데이터베이스 연결이 중간에 끊어질 수도 있습니다(긍정 오류, 잘린 데이터를 얻음).

생산자가 성공했는지 알아야 하는 경우 소비자를 시작하기 전에 생산자가 완료될 때까지 기다려야 합니다. 소비자가 아직 나타나지 않았으므로 출력을 저장해야 합니다.

출력에 널 바이트가 포함되지 않고 단 하나의 개행 문자로 끝나며 너무 크지 않은 경우 쉘 변수에 저장할 수 있습니다.

output=$(producer); producer_status=$?
if [ "$producer_status" -ne 0 ]; then
  echo >&2 "Producer failed with status $producer_status"
  exit "$producer_status"
fi
printf '%s\n' "$output" | consumer

zsh 및 기타 일부 셸(ksh93 및 bash 포함)에서는 마지막 줄을 consumer <<<"$output".

명령 대체는 후행 줄 바꿈을 제거한다는 점에 유의하십시오. 후행 빈 줄이 관련된 경우 해결 방법은 첫 번째 줄을 다음으로 변경하는 것입니다.

output=$(producer; ret=$?; echo .; exit "$?")
producer_status=$? output=${output%?}

$output그러면 후행 개행 문자(있는 경우)를 포함하여 전체 출력이 포함됩니다. 그런 다음 에 제공하는 printf %s "$output"대신 사용하십시오 .printf '%s\n' "$output"consumer

출력이 너무 크거나 널 바이트를 포함할 수 있는 경우 임시 파일에 저장하십시오.

답변2

DopeGhoti가 말했듯이,pipefail...단순히 파이프라인 체인의 어느 지점에서든 오류가 종료 코드에 대해 유지된다는 의미입니다.[관로].

오류 발생 시 스크립트를 종료하려면 를 사용하십시오 set -e.

파일이 생성되는 것을 방지하려면 임시 파일을 생성하고 성공 시 이름을 바꾸십시오. 예:

set -e 
psql $PG_HOST -At -F$'\t' -c \
    "SELECT * FROM mytable"  >  /tmp/mytable.txt~
                          # ^^^ cf. Useless Use of Cat
mv /tmp/mytable.txt~ /tmp/mytable.txt

나는 항상 사용만들다오류 발생 시 중지되고 다시 시작할 수 있는 파이프라인을 구축할 수 있기 때문입니다.

관련 정보