종료 코드와 오류 처리

ShellBeginner
지금 연습하기

소개

누군가에게 일을 부탁할 때마다 그 사람이 작업을 마친 뒤 작은 카드를 건넨다고 상상해 보세요.

  • **초록색 카드 (0)**는 "완벽하게 처리했습니다"를 의미합니다.
  • **빨간색 카드 (1-255)**는 "문제가 발생했습니다"를 의미합니다.

Linux 에서는 모든 명령이 정확히 이런 방식으로 동작합니다. 이를 종료 코드 (exit code) 또는 **종료 상태 (exit status)**라고 합니다.

  • 0: 성공
  • 0이 아님: 실패

대부분의 초보자는 이 코드를 확인하지 않으면 보이지 않기 때문에 무시합니다. 하지만 전문 스크립트 작성자는 종료 상태를 주의 깊게 확인합니다. 종료 상태는 명령과 스크립트 사이에서 성공 또는 실패를 알리는 셸의 주요 수단 중 하나이기 때문입니다.

이는 Unix 의 핵심 설계 방식입니다. 작은 프로그램들은 단순한 규칙을 사용해 서로 통신합니다. 텍스트는 표준 출력으로 전달되고, 성공 또는 실패는 종료 상태로 전달됩니다. 자동화에서 종료 코드가 중요한 이유가 바로 여기에 있습니다.

이 실습에서는 변수 $?를 사용해 이 비밀 카드를 읽고, 스크립트가 문제를 일으키기 전에 중지하는 방법을 배웁니다.

$?로 명령 상태 확인

보이지 않는 "성적표"를 어떻게 확인할까요? 명령을 실행한 직후 특수 변수 $?를 확인하면 됩니다.

먼저 성공하는 경우를 살펴보겠습니다.

터미널을 열고 파일을 목록으로 표시합니다.

ls -l

정상적으로 실행되었지요? 이제 "점수가 몇 점이었을까?"라고 물어보겠습니다.

echo $?

0이 표시됩니다. Linux 에서는 0 을 오류의 개수로 생각할 수 있습니다. 오류가 0 개라는 것은 완벽하게 성공했다는 뜻입니다.

이번에는 일부러 실패를 발생시켜 보겠습니다. 존재하지 않는 파일을 목록으로 표시합니다.

ls ghosts.txt

Linux 에서 파일을 찾을 수 없다는 오류 메시지가 표시됩니다. 이제 점수를 다시 확인합니다.

echo $?

2가 표시됩니다. 0 이 아니므로 실패입니다.

정확한 0 이 아닌 숫자는 명령과 상황에 따라 달라질 수 있습니다. 하지만 지금 기억해야 할 핵심 규칙은 간단합니다. 0은 성공이고, 그 외의 값은 실패입니다. 나중에 스크립트와 도구를 사용하다 보면 일부 프로그램이 서로 다른 종류의 문제를 나타내기 위해 여러 0 이 아닌 종료 코드를 사용하는 것을 확인하게 됩니다.

중요한 규칙: $?는 단기 기억만 저장합니다. $?는 바로 직전에 실행한 작업만 기억합니다. ls를 실행해 실패한 다음 echo "hello"를 실행하고 $?를 확인하면, echo가 성공했기 때문에 0이 표시됩니다. 반드시 명령을 실행한 직후 확인해야 합니다.

실패하는 스크립트 만들기

여기에는 위험 요소가 있습니다. 기본적으로 스크립트는 빨간색 카드를 무시하고 계속 실행합니다.

다음과 같은 스크립트를 생각해 보세요.

  1. 백업을 만듭니다.
  2. 원본 파일을 삭제합니다.

1 단계가 실패하면 (백업 공간이 가득 찬 경우) 2 단계가 계속 실행되어 모든 파일을 잃게 됩니다.

이 "눈먼 스크립트"를 직접 시뮬레이션해 보겠습니다.

copy_script.sh를 만듭니다.

nano copy_script.sh

다음 코드를 입력합니다. 이 코드는 존재하지 않는 파일을 복사한 뒤 성공했다고 알립니다.

#!/bin/bash

## Attempt to copy a ghost
cp ghost_file.txt destination.txt

## Print a happy message
echo "Script finished execution"

파일을 저장하고 종료합니다. 실행 권한을 부여합니다.

chmod +x copy_script.sh

실행합니다.

./copy_script.sh

cp의 오류 메시지가 표시된 다음 "Script finished execution"도 표시됩니다. 스크립트는 실패했지만 계속 실행된 것입니다!

스크립트 자체의 점수를 확인합니다.

echo $?

0이 반환됩니다. 왜 그럴까요? 마지막 명령 (echo) 이 성공했기 때문입니다. 이 스크립트는 거짓말을 하고 있습니다. 주요 작업에는 실패했지만 시스템에는 성공했다고 보고합니다.

여기서 중요한 점을 배울 수 있습니다. 셸 스크립트에도 종료 상태가 있으며, 특별히 처리하지 않으면 종료 상태는 실행된 마지막 명령의 종료 상태가 되는 경우가 많습니다. 따라서 스크립트 앞부분에서 발생한 실패가 실수로 숨겨질 수 있습니다.

오류 처리 구현

스크립트가 빨간불을 만나면 멈추도록 만들어야 합니다.

일반적으로 다음과 같은 구조를 사용합니다. "명령 X 를 실행합니다. 종료 코드가 0 이 아니면 즉시 중단합니다."

[ $? -ne 0 ] 구문은 여기에서 대괄호 형식으로 작성한 test 명령을 사용합니다. -ne는 숫자에서 "같지 않음"을 의미합니다. 따라서 셸은 "이전 명령의 종료 상태가 0 과 같지 않은가?"라고 확인합니다.

copy_script.sh를 편집합니다.

nano copy_script.sh

내용을 다음과 같이 변경합니다.

#!/bin/bash

cp ghost_file.txt destination.txt

## Check if the score is NOT equal (-ne) to 0
if [ $? -ne 0 ]; then
  echo "Error: The copy operation failed!"
  exit 1
fi

echo "Script finished execution"

코드 해석:

  • if [ $? -ne 0 ]: 검사 장치가 카드를 확인합니다.
  • exit 1: 빨간색 버튼입니다. 스크립트를 즉시 종료하고 전역 점수를 1(오류) 로 설정합니다.

exit 명령은 현재 셸 스크립트를 종료하고, 해당 숫자를 스크립트를 실행한 대상에 반환합니다. 실행한 대상은 터미널, 다른 스크립트 또는 자동화 시스템일 수 있습니다. 즉, 로컬에서 실행만 중지하는 것이 아니라 외부 시스템에 상태도 보고하는 것입니다.

파일을 저장하고 종료합니다.

다시 실행합니다.

./copy_script.sh

스크립트는 오류를 출력하고 종료됩니다. "Script finished execution"은 출력하지 않습니다.

점수를 확인합니다.

echo $?

1이 표시됩니다. 이제 스크립트가 실패 사실을 정확하게 보고합니다.

요약

이제 명령의 비밀 언어를 읽는 방법을 배웠습니다.

이 실습에서는 다음 내용을 연습했습니다.

  1. 성적표 읽기: $?를 사용해 명령이 성공했는지 (0), 실패했는지 (1-255) 확인합니다.
  2. 거짓말하는 스크립트 드러내기: 주의하지 않으면 스크립트가 오류를 숨길 수 있다는 점을 확인합니다.
  3. 심판 역할 수행하기: 문제가 발생하면 exit 1을 사용해 실행을 중지합니다.

이 "확인 후 종료" 패턴이 허술한 스크립트와 전문적인 스크립트를 구분합니다.