Bash 5.x · POSIX sh와 차이 표시

셸의 조건문과 반복문을 읽는 순서

if가 검사하는 종료 상태부터 case, break, read, trap까지 작은 예제로 확인합니다.

if는 명령이 성공했는지 확인합니다

if 뒤에는 명령이 옵니다. 종료 상태가 0이면 then 부분을 실행합니다. 대괄호도 test와 같은 검사를 수행하는 명령이므로 인자 사이에 공백이 필요합니다.

value=12
if [ "$value" -gt 10 ]; then
    printf '%s\n' 'greater than 10'
fi
if [ "$value" = 12 ] && [ -n "$value" ]; then
    printf '%s\n' 'same text, not empty'
fi
표현검사하는 내용
-eq, -lt, -gt정수의 같음·작음·큼입니다. 임의 문자열을 바로 넣으면 숫자 검사에 실패할 수 있습니다.
=, !=문자열 비교입니다. [ … ]에서 숫자 크기를 비교할 때 >를 쓰면 리다이렉션으로 해석될 수 있습니다.
-z, -n문자열이 비어 있는지, 비어 있지 않은지 확인합니다.
&&, ||앞 명령이 성공하거나 실패했을 때 뒤 명령을 실행합니다. XOR 연산자가 아닙니다.

여러 조건은 [ … ] && [ … ]처럼 나누면 인자 수에 따라 의미가 달라지는 -a/-o 표현을 피할 수 있습니다. 검사만 성공했다고 뒤의 파일 작업까지 성공하는 것은 아닙니다.

break는 가장 가까운 반복문을 끝냅니다

for item in alpha stop omega; do
    if [ "$item" = stop ]; then
        break
    fi
    printf '%s\n' "$item"
done
printf '%s\n' done

alpha와 done이 출력됩니다. if의 조건이 맞을 때 break를 실행하지만, 끝나는 대상은 for 반복문입니다. continue는 현재 반복의 나머지를 건너뜁니다. 루프 밖에서 break를 일반 분기 종료 명령처럼 쓰지 않습니다.

반복문 한 바퀴의 실행 순서
  1. item에 다음 값 저장alpha, stop, omega 순서로 후보를 받습니다.
  2. stop인지 검사참이면 반복문 밖으로 이동합니다.
  3. 그 밖의 값 출력다음 반복으로 돌아갑니다.

상자의 번호는 실행 순서입니다. stop에서 3번을 실행하지 않고 루프 뒤의 done 출력으로 이동합니다.

read의 실패와 빈 입력을 구분합니다

printf 'name: '
if IFS= read -r name; then
    case "$name" in
        '') printf '%s\n' 'empty input' ;;
        quit|exit) printf '%s\n' 'stop requested' ;;
        *) printf 'name=%s\n' "$name" ;;
    esac
else
    printf '%s\n' 'input ended before a complete line' >&2
fi

IFS=는 양 끝의 공백을 보존하고, -r은 역슬래시를 이스케이프로 처리하지 않도록 합니다. Enter만 누른 빈 줄은 정상 입력입니다. EOF 등으로 read가 실패한 경우와 구분해야 합니다. 파일의 마지막 줄에 개행이 없으면 값이 들어와도 read가 실패할 수 있으므로 파일 순회에서는 그 경우를 별도로 처리합니다. case는 문자열과 패턴을 비교하며 ;;에서 해당 분기를 끝냅니다.

Bash 전용 문법과 출력·종료 처리를 구분합니다

#!/usr/bin/env bash
trap 'printf "%s\n" "interrupted" >&2; exit 130' INT
path='dir/sample.txt'
printf 'file=%s\n' "${path##*/}"
printf 'without extension=%s\n' "${path%.*}"
printf '%s\n' {one,two,three}

##는 가장 길게 맞는 접두 패턴을, %는 가장 짧게 맞는 접미 패턴을 제거합니다. ${0%/*}도 문자열 처리이므로 슬래시가 없는 호출에서는 디렉터리를 알아내지 못합니다. pushd/popd, 브레이스 확장, 대소문자 변환 ${name^^}, [[ … ]], (( … ))는 sh에서 그대로 된다고 가정하지 않습니다.

trap은 지정한 시그널이나 셸 이벤트에서 실행할 명령을 등록합니다. SIGKILL과 SIGSTOP은 잡을 수 없습니다. EXIT trap도 전원 중단이나 SIGKILL까지 처리해 주지는 않습니다. echo의 -e 동작에 의존하기보다 printf에 고정된 형식과 값을 별도 인자로 전달합니다.

확인한 문서

Bash 5.x · POSIX sh와 차이 표시