[Linux 셸 스크립트] bash - 130 파이프 처리로 각 명령어 종료 상태값 조사하기
본문 바로가기
IT 이야기/Linux 셸 스크립트

[Linux 셸 스크립트] bash - 130 파이프 처리로 각 명령어 종료 상태값 조사하기

by 찬찬이 아빠 2021. 7. 13.
반응형
  1. 사용 명령어

(1) echo

 

  2. 키워드 & 사용처

(1) 키워드

파이프, 종료 스테이터스

 

(2) 사용처

파이프 처리 중에 어떤 명령어 종료 스테이터스를 확인해서 명령어의 성공/실패를 판단하고 싶을 때 사용합니다.

 

  3. 실행 예제
$ ./pipestatus.sh
[ERROR] sort-data.sh에 실패했습니다.

 

 

  4. 스크립트

#!/bin/bash

 

# 다음과 같은 처리를 하는 경우를 가정

# script.sh : 데이터 출력

# sort-data.sh : 데이터 정렬

# calc.sh : 출력 데이터 계산

./script.sh | ./sort-data.sh | ./calc.sh > output.txt         

 

# 다른 명령어를 실행하면 PIPESTATUS 값이 사라지므로 결과를 복사해둠

pipe_status=("${PIPESTATUS[@]}")           

 

# 파이프 처리 중에 명령어 성공, 실패 확인

# sort-data.sh 종료 스테이터스가 0이 아닌지 확인

if [ "${pipe_status[1]}" -ne 0 ]; then                 

    echo "[ERROR] sort-data.sh에 실패했습니다." >&2

fi

 

 

  5. 해설

이 스크립트는 파이프 처리 중에 에러가 발생했는지 확인해서 에러가 발생하면 에러 메시지를 출력합니다.

 

여기서는 script.sh -> sort-data.sh -> calc.sh라는 세 스크립트를 순서대로 실행해서 어떤 데이터를 처리한 뒤에 그 결과를 output.txt라는 파일에 출력한다고 가정합니다. 여기서 sort-data.sh는 실패하기도 하는데 그 다음 calc.sh에서 하는 계산은 정렬이 필수가 아니므로 에러 발생 여부와 관계없이 실행 가능하다고 가정합니다. 다만 정렬에 실패하면 종료 스테이터스가 0이 아니므로 이걸 검출해서 에러 메시지만 출력하고 싶다고 합시다.

 

명령어 종료 스테이터스 $?를 이용하는 예제는 앞에서 많이 다루었지만 파이프 처리는 도중에 명령어 종료 스테이터스를 $?로 취득할 수 없습니다. 변수 $?는 파이프 라인 마지막에 실행된 명령어 종료 스테이터스만 대입되기 때문에 에서 마지막 calc.sh 종료 스테이터스만 확인할 수 있습니다.

 

그러나 bash 내장 변수인 PIPESTATUS를 이용하면 직접 파이프라인 처리의 모든 종료 스테이터스를 취득할 수 있습니다. PIPESTATUS는 배열 변수라서 0번에는 파이프 첫번째 종료 스테이터스가, 1번에는 파이프 두 번째 종료 스테이터스가 들어 있습니다.

서술 예 설명
${PIPESTATUS[0]} 파이프 처리 첫 번째(script.sh) 종료 스테이터스
${PIPESTATUS[1]} 파이프 처리 두 번째(sort-data.sh) 종료 스테이터스
${PIPESTATUS[2]} 파이프 처리 세 번째(calc.sh) 종료 스테이터스

의 ${PIPESTATUS[@]}로 사용하는 배열 첨자 @은 배열 전체를 의미합니다. 전체를 ()로 싸서 배열 전체를 셸 변수에 복사합니다.

 

은 sort-data.sh 종료 스테이터스를 ${PIPESTATUS[1]}로 취득해서 TEST 명령어의 다른 값인지 확인하는 -ne 연산자로 0과 비교합니다. 종료 스테이터스가 0이 아니면 에러 메시지를 표시합니다.

 

이렇게 해서 파이프 처리 중에 명령어 종료 스테이터스를 취득할 수 있습니다.

 

 

  6. PIPESTATUS 이용 시 주의점

변수 PIPESTATES를 이용할 때 주의해야 하는 것은 어떤 명령어를 실행할 때마다 변수 PIPESTATUS가 늘 변경된다는 점입니다. 예를 들어 다음은 파이프 처리하는 세 명령어 종료 스테이터스를 ECHO 명령어로 확인하는(하려고 했던) 스크립트 입니다. 하지만 이 스크립트는 잘못 작성되었습니다.

#!/bin/bash

./script.sh | ./sort-data.sh | ./calc.sh > output.txt

echo ${PIPESTATUS[0]}
echo ${PIPESTATUS[1]}            A
echo ${PIPESTATUS[2]}            B

이걸 실행하면 A와 B의 echo 명령어에 아무것도 표시되지 않습니다.

$ ./list2.sh
0

 

이것은 파이프를 사용하지 않는 명령어 처리에서도 변수 PIPESTATUS는 0개의 파이프 처리로 보고 늘 변경되기 때문입니다. 따라서 A에서는 직전의 echo 명령어의 두 번째 파이프 처리 종료 스테이터스를 얻으려고 하는데 그런 처리가 존재하지 않으므로 공백문자열을 출력합니다. B도 마찬가지입니다. 이렇듯 어떤 명령어를 실행할 때마다 PIPESTATUS는 덮어쓰기로 변경됩니다. 따라서 예제에서는 PIPESTATUS를 일단 셸 변수 pipe_status에 그대로 복사합니다.

 

 

<주의사항>

셸 변수 PIPESTATUS는 sh에는 없는 bash 고유 셸 변수 입니다. 그 외에도 몇 가지 bash 고유 셸 변수가 있는데 그 중 몇가지는 아래와 같습니다.

셸 변수명 의미
BASH 현재 실행하고 있는 bash를 실행할 때의 전체 경로
DIRSTACK 디렉터리 스택 내용(배열 변수)
SHEELOPTS 유효한 셸 옵션(쉼표로 구분)
SECONDS 셸이 실행된 초
HOSTNAME 호스트명
UID 셸을 실행한 사용자 ID
GROUPS 현재 사용자가 속한 그룹 목록(배열 변수)

 

 

참고서적 : 유닉스 리눅스 셸 스크립트 예제 사전

반응형

댓글