Shell Script

Shell Script - 에러 처리

사실 나도 모름 2024. 1. 10. 02:27
  1. set
  2. trap
  3. 부록

 

 

 

이번에는 쉘 스크립트의 에러 처리를 알아보자.

스크립트를 실행하다가 에러가 발생하면 당연히 문제가 많이 생긴다.

에러 처리를 위한 대표적인 명령 중 set과 trap을 살펴보자.

 

1. set

set 명령은 쉘에서 사용되는 옵션 및 위치 매개변수의 값을 설정 또는 해제하거나 쉘 변수의 이름 및 값들을 출력하는 데 사용된다.

 

대표적으로 다음과 같은 옵션을 갖는다.

  • -a: 내보내기(export)를 위해 수정되거나 생성된 변수를 표시합니다.
  • -b: 작업 종료를 즉시 알립니다.
  • -e: 명령이 0이 아닌 상태로 종료되면 바로 종료합니다.
  • -f: 파일 이름 생성(globbing)을 비활성화합니다.
  • -h: 명령이 찾아질 때마다 명령의 위치를 기억합니다.
  • -k: 모든 할당 인수를 명령의 이름 앞뒤 상관없이 환경에 배치합니다.
  • -m: 작업 제어가 활성화됩니다.
  • -n: 명령을 읽지만 실행하지 않습니다.
  • -o option-name: option-name에 해당하는 변수를 설정합니다.
  • -p: 실제 및 유효한 사용자 ID가 일치하지 않을 때마다 켜집니다. 이 경우 $ENV 파일의 처리 및 쉘 함수 가져오기가 비활성화됩니다.
  • -t: 하나의 명령을 읽고 실행한 후에 종료합니다.
  • -u: 미설정된 변수를 대체할 때 에러로 취급합니다.
  • -v: 쉘 입력 라인을 읽을 때마다 출력합니다.
  • -x: 명령 및 해당 인수를 실행할 때 출력합니다.
  • -B: 쉘이 중괄호 확장을 수행합니다.
  • -C: 설정된 경우 출력 리디렉션으로 기존의 일반 파일을 덮어쓰는 것을 허용하지 않습니다.
  • -E: 설정된 경우 ERR 트랩이 쉘 함수에 상속됩니다.
  • -H: ! 스타일의 히스토리 치환을 사용합니다. 이 플래그는 쉘이 대화형일 때 기본적으로 설정됩니다.
  • -P: 설정된 경우 명령을 실행할 때 cd와 같은 명령에서 심볼릭 링크를 해석하지 않습니다.
  • -T: 설정된 경우 DEBUG 및 RETURN 트랩이 쉘 함수에 상속됩니다.
  • --: 나머지 인수를 위치 매개변수에 할당합니다. 나머지 인수가 없으면 위치 매개변수가 설정되지 않습니다.
  • -: 나머지 인수를 위치 매개변수에 할당합니다. 이 경우 -x와 -v 옵션이 꺼집니다.
  • +를 사용하면 해당 플래그가 해제됩니다. 또한 쉘을 시작할 때 옵션을 사용하여 쉘을 호출할 수 있으며, 현재 설정된 플래그는 $- 변수에서 확인할 수 있습니다. 인수를 지정하지 않으면 모든 쉘 변수가 출력됩니다.

 

이 중에서 자주 사용하는 옵션은 -e, -u, -x, -o, -n, -m 등이다.

 

하나씩 실습으로 확인해보자.

-e 옵션(errexit) : 종료코드가 0이 아닌 결과가 나오면 즉시 스크립트 종료

#!/bin/bash

set -e

ls nothing   # 없는 디렉토리
echo "hello"   # 실행하지 않음

echo 라인은 실행되지 않았다.

 

 

-u 옵션(nounset) : 존재하지 않는 변수가 사용되면 즉시 스크립트 종료

#!/bin/bash

set -u

echo "moving a file $abcdefg"	# 존재하지 않는 변수
echo "hello"   # 실행하지 않음

echo 라인은 실행되지 않았다.

 

 

-x 옵션(xtrace) : 실행되는 명령도 함께 출력

#!/bin/bash

set -x

ls -l /
echo "hello"

결과와 함께 실행한 명령도 함께 출력

 

 

-o option-name 옵션(set option) : 특정한 쉘 옵션을 설정. errexit, nounset, xtrace 등을 개별적으로 설정 가능

#!/bin/bash

set -o errexit

aaa
echo "hello"

-o errexit는 -e와 동일한 역할

 

 

-n 옵션(noexec) : 명령을 읽지만 실행하지 않음. 문법 체크 및 유효성 검사에 사용

#!/bin/bash

set -n

echo "starting script"
ABC=$(date +%Y%m%d)

mkdir abc
touch /root/sh/abc/test-${ABC}.txt
cat << EOF | tee /root/sh/abc/test-${ABC}.txt
hello
world
${ABC}
EOF
ls /root/sh/abc/test-${ABC}.txt

문제 없음

 

 

-m 옵션(monitor) : 작업 제어를 활성화

작업 제어를 활성화하면 fg, bg, jobs와 같은 프로세스 전환 명령을 사용하여 제어할 수 있다.

#!/bin/bash

set -m

# 작업 제어를 활성화하면서 서브쉘에서 백그라운드 작업 실행
(
  sleep 3 &
  echo "Sub shell background job started"

  wait
  echo "Sub shell background jpb completed"
)

# 현재 쉘에서 백그라운드 작업 실행
sleep 5 &
sleep 10 &
echo "Main shell background job started"

# 현재 쉘에서 실행한 첫번째 백그라운드 작업 포그라운드로 전환
fg 1
echo "Main shell first background job completed"

# 모든 백그라운드 작업이 완료될 때까지 대기
wait

echo "All jobs completed"

sleep 명령의 진행을 직접 보여주진 못하지만 순차적으로 된다.

 

 

 

 


2. trap

trap 명령어는 쉘 스크립트에서 신호(signal)를 처리하거나 특정 이벤트가 발생할 때 실행할 명령을 지정하는 데 사용된다.

주로 스크립트에서 오류 처리나 정리 작업 등에 활용된다.

기본 문법
trap COMMAND SIGNALS

 

 

시그널(SIGNALS)의 종류는 다음과 같다.

  • EXIT: 스크립트나 셸이 종료될 때 발생하는 시그널.
  • DEBUG: 명령어 실행 전에 디버그 정보를 출력할 때 발생하는 시그널.
  • ERR: 명령어 실행 중 에러가 발생했을 때 발생하는 시그널.
  • RETURN: 함수가 종료되었을 때 발생하는 시그널.

 

다음은 trap을 사용한 간단한 예시다.

#!/bin/bash

on_error(){
        echo "ERR: occured errror" >&2
        exit 1
}

trap on_error ERR

ls aaaaaaaaa 2> /dev/null       # 없는 디렉토리

echo "process completed"        # 실행되지 않음

사용자 정의 에러 메시지 출력

 

on_error라는 사용자 정의 함수를 정의하고 trap 명령에서 on_error와 ERR이라는 에러 신호가 발생되면 트리거하는 방식이다.

이와 같이 trap 명령을 통해 스크립트 전체의 명령에 대해 에러가 발생하면 사용자 정의 함수를 실행하여 에러 메시지를 출력하고 스크립트를 종료하도록 구성할 수 있다.

 

 

 

 

 

 


3. 부록

내가 작성한 에러 처리를 첨가한 간단한 스크립트다. 

이 스크립트는 VM에 새로운 디스크를 추가했을 때 기존의 논리 볼륨(lv)을 확장하는 스크립트다.

 

에러 처리 적용 전

#!/bin/bash
# description: extend volume

recent_volume=$(lsblk -o NAME,TYPE,MOUNTPOINT | awk '/disk/ && $3 == "" && $1 != "sda" {lastLine="/dev/"$1} END {print lastLine}')
sudo pvcreate $recent_volume
sudo vgextend ubuntu-vg $recent_volume
sudo lvextend /dev/ubuntu-vg/ubuntu-lv $recent_volume
sudo lvextend -l +100%FREE /dev/ubuntu-vg/ubuntu-lv
sudo resize2fs /dev/ubuntu-vg/ubuntu-lv
sudo vgdisplay
sudo lvdisplay

 

 

 

에러 처리 적용 후

#!/bin/bash
# description: extend volume

log_file="/var/log/extend_volume.log"

set -e

on_error() {
        echo "에러가 발생하였습니다." >&2
}

trap on_error ERR

recent_volume=$(lsblk -o NAME,TYPE,MOUNTPOINT | awk '/disk/ && $3 == "" && $1 != "sda" {lastLine="/dev/"$1} END {print lastLine}')

if [ -z "$recent_volume" ]; then
        echo "값이 비었습니다."
        exit 1
fi

set +e
echo "추가된 볼륨 ${recent_volume}을 이용하여 확장합니다." || on_error >> "$log_file"
set -e

sudo pvcreate $recent_volume >> "$log_file" 2>&1
sudo vgextend ubuntu-vg $recent_volume >> "$log_file" 2>&1
sudo lvextend /dev/ubuntu-vg/ubuntu-lv $recent_volume >> "$log_file" 2>&1
sudo lvextend -l +100%FREE /dev/ubuntu-vg/ubuntu-lv >> "$log_file" 2>&1
sudo resize2fs /dev/ubuntu-vg/ubuntu-lv >> "$log_file" 2>&1
sudo vgdisplay >> "$log_file" 2>&1
sudo lvdisplay >> "$log_file" 2>&1

echo "The volume was successfully extended."

'Shell Script' 카테고리의 다른 글

Shell Script 기초(7)  (0) 2023.11.28
Shell Script 기초(6)  (0) 2023.11.27
Shell Script 보안 - 코드 인젝션 취약점  (0) 2023.11.24
Shell Script 기초(5)  (0) 2023.11.24
Shell Script 기초(4)  (0) 2023.11.24