- set
- trap
- 부록
이번에는 쉘 스크립트의 에러 처리를 알아보자.
스크립트를 실행하다가 에러가 발생하면 당연히 문제가 많이 생긴다.
에러 처리를 위한 대표적인 명령 중 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" # 실행하지 않음
-u 옵션(nounset) : 존재하지 않는 변수가 사용되면 즉시 스크립트 종료
#!/bin/bash
set -u
echo "moving a file $abcdefg" # 존재하지 않는 변수
echo "hello" # 실행하지 않음
-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"
-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"
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 |