Bash 입문자를 위한 핵심 요약 정리 (Shell Script)

bash logo

Bash는 리눅스 및 macOS와 같은 유닉스 계열 운영 체제의 기본 쉘(Shell)입니다. Bash 스크립트를 사용하면 반복적인 작업을 자동화하고, 시스템 관리 작업을 효율적으로 수행할 수 있습니다. 이 가이드에서는 Bash 입문자를 위해 기본적인 문법과 유용한 팁들을 예제와 함께 간단하게 정리했습니다. “이런 것도 있구나” 정도로 가볍게 이해하고 넘어가세요.

1. 첫 시작: Hello World 출력

고전적인 “Hello World” 출력부터 시작해봅시다. hello.sh 파일을 만들고 아래 코드를 작성하세요.

#!/usr/bin/env bash

echo "Hello, world!"      # 출력: Hello, world!
printf "Hello, world!\n"   # 줄바꿈을 명시적으로 추가. 출력: Hello, world!
printf "%s %s\n" hello world # C 스타일 포맷팅. 출력: hello world

실행 방법:

  1. 터미널에서 chmod +x hello.sh 명령어로 실행 권한을 부여합니다. (또는 chmod 700 hello.sh는 소유자에게만 실행 권한 부여)
  2. ./hello.sh 명령어로 스크립트를 실행합니다.

설명:

  • #!/usr/bin/env bash: 스크립트 실행에 사용할 Bash 인터프리터 경로를 지정합니다. (Shebang, 셔뱅)
  • echo: 문자열을 출력하고 자동으로 줄바꿈합니다.
  • printf: C 언어의 printf와 유사하게 포맷 문자열을 사용하여 출력합니다.

2. 주석 (Comments)

# 기호로 시작하는 줄은 주석으로 처리되어 실행되지 않습니다. 코드 설명이나 임시 코드 비활성화에 사용됩니다.

3. 함수 (Function)

# 'function' 키워드는 생략 가능
my_function() {
  echo "함수 호출됨"
  echo "전달된 인자: $@"
}

# 함수 호출 (정의보다 뒤에 위치해야 함)
my_function
my_function "arg1" "arg2" # 인자 전달.  출력: arg1 arg2

설명:

  • 함수 정의는 function 함수명() { ... } 또는 함수명() { ... } 형식으로 합니다.
  • 함수 호출은 함수 이름을 사용합니다.
  • 함수 호출 코드는 함수 정의보다 뒤에 있어야 합니다.
  • $@: 함수에 전달된 모든 인자를 나타냅니다.

4. 변수 (Variable)

# 전역 변수
global_var="Hello"

my_function() {
  # 지역 변수
  local local_var="World" # local 변수는 함수 내에서만 유효. 함수 밖의 같은 이름의 변수에 영향 X
  echo "지역 변수: $local_var"  # 출력: 지역 변수: World
  global_var="Modified Global" # 전역 변수 수정
}

my_function()
echo "전역 변수: $global_var" # 출력: 전역 변수: Modified Global

# 환경 변수 (자식 스크립트에서도 사용 가능)
export MY_ENV_VAR="Environment Value"

# 자식 스크립트 실행 예시 (child.sh)
# ./child.sh  # child.sh 스크립트 안에서  echo $MY_ENV_VAR 실행

설명:

  • 변수 선언/할당 시 = 앞뒤에 공백이 없어야 합니다.
  • 변수는 기본적으로 전역 변수입니다.
  • 함수 내에서 local 키워드를 사용하여 지역 변수를 선언할 수 있습니다.
  • export를 사용하여 환경 변수를 설정하면, 현재 스크립트뿐만 아니라 자식 스크립트에서도 사용할 수 있습니다.
  • 예약 변수(Reserved Variable) 사용 시 주의해야 합니다. (예: HOME, PATH, USER 등). 환경 변수는 주로 .bash_profile, .bashrc, 또는 시스템 설정 파일에서 정의합니다.

5. 예약 변수 (Reserved Variable)

Bash에는 미리 정의된 예약 변수들이 있습니다. 자주 사용되는 예약 변수들은 다음과 같습니다.

변수 설명
HOME 사용자의 홈 디렉토리
PATH 실행 파일을 찾을 경로
PWD 현재 작업 디렉토리
USER 현재 사용자 이름
UID 현재 사용자 ID
SHELL 현재 사용 중인 쉘 경로
FUNCNAME 현재 함수 이름 (함수 내부에서 사용)
SECONDS 스크립트 실행 시간 (초)
RANDOM 랜덤 정수 (0-32767)
$$ 현재 스크립트의 프로세스 ID (PID)
$? 마지막으로 실행한 명령어의 종료 상태 (0: 성공, 0 이외: 실패)
$! 마지막으로 실행한 백그라운드 프로세스의 PID

더 많은 예약 변수는 Bash Reference Manual을 참고하세요.

6. 위치 매개변수 (Positional Parameters)

스크립트나 함수에 전달된 인자(arguments)를 참조하는 데 사용됩니다.

변수 설명
$0 실행된 스크립트 이름
$1, $2, … 첫 번째, 두 번째, … 인자. 10번째 이상은 ${10}, ${11} 처럼 중괄호 사용
$* 모든 인자를 하나의 문자열로 합쳐서 표시 (“arg1 arg2 …”)
$@ 모든 인자를 각각의 개별적인 문자열로 표시 (“arg1” “arg2” …)
$# 전달된 인자의 개수

7. 특수 매개변수 (Special Parameters)

위에서 설명한 $$, $?, $! 외에도 다른 특수 매개변수들이 있습니다.

변수 설명
$- 현재 쉘에 설정된 옵션 플래그
$_ 이전에 실행된 명령어의 마지막 인자

8. 매개변수 확장 (Parameter Expansion)

변수의 값을 다양하게 조작하고 활용하는 방법입니다.

string="abc-efg-123-abc"
표현식 설명 예시 (string="abc-efg-123-abc")
${변수} 변수 값 echo ${string}abc-efg-123-abc
${변수:위치} 위치부터 끝까지 부분 문자열 echo ${string:4}efg-123-abc
${변수:위치:길이} 위치부터 길이만큼 부분 문자열 echo ${string:4:3}efg
${#변수} 문자열 길이 echo ${#string}15
${변수:-단어} 변수가 unset 또는 null이면 ‘단어’ 반환, 아니면 변수 값 echo ${unset_var:-default} → default
${변수-단어} 변수가 unset이면 ‘단어’ 반환, 아니면 변수 값 echo ${unset_var-default} → default
${변수:=단어} 변수가 unset 또는 null이면 ‘단어’ 할당 후 반환, 아니면 변수 값 echo ${unset_var:=default}; echo $unset_var → default default
${변수=단어} 변수가 unset이면 ‘단어’ 할당 후 반환, 아니면 변수 값 echo ${unset_var=default}; echo $unset_var → default default
${변수:?메시지} 변수가 unset 또는 null이면 메시지 출력 후 종료 echo ${unset_var:?Error} → (스크립트 종료) Error
${변수?메시지} 변수가 unset이면 메시지 출력 후 종료 echo ${unset_var?Error} → (스크립트 종료) Error
${변수:+단어} 변수가 설정되어 있으면 ‘단어’ 반환, 아니면 null echo ${string:+exists} → exists
${변수+단어} 변수가 설정되어 있으면 ‘단어’ 반환, 아니면 null. ${변수:+단어}와 동일. echo ${string+exists} → exists
${변수#패턴} 앞에서부터 가장 짧은 패턴 일치 제거 echo ${string#*-}efg-123-abc
${변수##패턴} 앞에서부터 가장 긴 패턴 일치 제거 echo ${string##*-}abc
${변수%패턴} 뒤에서부터 가장 짧은 패턴 일치 제거 echo ${string%-*}abc-efg-123
${변수%%패턴} 뒤에서부터 가장 긴 패턴 일치 제거 echo ${string%%-*}abc
${변수/패턴/대체} 첫 번째 패턴 일치 대체 echo ${string/abc/XYZ}XYZ-efg-123-abc
${변수//패턴/대체} 모든 패턴 일치 대체 echo ${string//abc/XYZ}XYZ-efg-123-XYZ
${변수/#패턴/대체} 문자열 시작 부분에서 패턴 일치 대체 echo ${string/#abc/XYZ}XYZ-efg-123-abc
${변수/%패턴/대체} 문자열 끝 부분에서 패턴 일치 대체 echo ${string/%abc/XYZ}abc-efg-123-XYZ
${!prefix*} 또는 ${!prefix@} prefix로 시작하는 모든 변수 이름 (var1=1; var2=2;) echo ${!var*} → var1 var2

9. 배열 (Array)

# 배열 선언 (declare -a는 필수는 아님)
declare -a my_array

# 배열 초기화
my_array=("apple" "banana" "cherry")

# 인덱스를 사용한 접근
echo ${my_array[0]}  # 첫 번째 요소 출력 (apple)

# 배열 전체 출력
echo ${my_array[@]}  # 모든 요소 출력 (apple banana cherry)

# 배열 길이
echo ${#my_array[@]} # 요소 개수 출력 (3)

# 요소 추가
my_array+=("date")   # 배열 끝에 요소 추가
my_array[4]="fig"    # 특정 인덱스에 요소 추가 (중간 인덱스 비워도 됨)

# 배열 복사
new_array=("${my_array[@]}")

# 요소 삭제
unset my_array[1]    # 두 번째 요소 삭제
unset my_array       # 배열 전체 삭제

주의: Bash 배열은 0부터 시작하는 인덱스를 사용하며, 1차원 배열만 지원합니다.

10. 변수 타입 지정 (Variable Types)

Bash는 기본적으로 변수를 문자열로 취급하지만, declare (또는 typeset) 명령어를 사용하여 타입을 지정할 수 있습니다. 하지만 Bash의 타입 지정은 엄격하지 않습니다.

declare -i num=10      # 정수 (integer)
declare -r readonly_var="Readonly"  # 읽기 전용 (readonly)
declare -a array_var   # 배열 (array)
declare -x export_var="Exported"  # 환경 변수 (export)
declare -f  # 정의된 모든 함수 목록
declare -f function_name # 특정 함수 정의
  • -i: 정수
  • -r: 읽기 전용(readonly)
  • -a: 배열
  • -x: 환경 변수(export)
  • -f: 함수

declare를 명시적으로 사용하는 것보다 변수 할당 시 타입을 자연스럽게 지정하는 방식을 추천합니다. (예: num=10 (정수), my_array=("a" "b") (배열))

11. 연산자 (Operators)

11.1. 논리 연산자 (Logical Operators)

연산자 설명 예시
&& AND (그리고) [ condition1 ] && [ condition2 ]
|| OR (또는) [ condition1 ] || [ condition2 ]
! NOT (부정) ! [ condition ]

11.2. 산술 연산자 (Arithmetic Operators)

연산자 설명
+, -, *, / 더하기, 빼기, 곱하기, 나누기
** 거듭제곱
% 나머지
+=, -=, *=, /=, %= 복합 대입 연산자

11.3. 비트 연산자 (Bitwise Operators)

연산자 설명
<< 왼쪽 시프트
>> 오른쪽 시프트
& 비트 AND
| 비트 OR
~ 비트 NOT (단항)
^ 비트 XOR
<<=, >>=, &=, |=, ^= 복합 대입 연산자 (비트)

11.4. 기타 연산자

연산자 설명
, 콤마 연산자: 여러 표현식을 순차적으로 실행

12. 비교 (Comparison)

12.1. 정수 비교 (Integer Comparison)

연산자 설명 (( )) 또는 [[ ]]에서 사용 [ ]에서 사용
-eq 같음 (equal) == 또는 = -eq
-ne 같지 않음 (not equal) != -ne
-gt 큼 (greater than) > -gt
-ge 크거나 같음 (greater than or equal) >= -ge
-lt 작음 (less than) < -lt
-le 작거나 같음 (less than or equal) <= -le

12.2. 문자열 비교 (String Comparison)

연산자 설명 예시
= 또는 == 같음 [[ "$str1" == "$str2" ]]
!= 같지 않음 [[ "$str1" != "$str2" ]]
< 사전순으로 앞섬 (ASCII) [[ "$str1" < "$str2" ]]
> 사전순으로 뒤섬 (ASCII) [[ "$str1" > "$str2" ]]
-z 문자열이 비어있음 (길이 0) [ -z "$str" ]
-n 문자열이 비어있지 않음 [ -n "$str" ]

12.3. 파일 비교 (File Test Operators)

연산자 설명
-e file 파일이 존재함
-f file 일반 파일
-d file 디렉토리
-s file 파일 크기가 0보다 큼
-r file 읽기 가능
-w file 쓰기 가능
-x file 실행 가능
-h file 또는 -L file 심볼릭 링크
file1 -nt file2 file1file2보다 최신
file1 -ot file2 file1file2보다 오래됨
file1 -ef file2 file1file2가 같은 파일을 가리킴 (하드 링크)

더 많은 파일 비교 연산자는 man test 또는 help test 명령으로 확인할 수 있습니다.

13. 반복문 (Loops)

  • break: 반복문 종료
  • continue: 다음 반복으로 건너뜀

13.1. for 루프

# 리스트 순회
for item in apple banana cherry; do
  echo "$item"
done

# C 스타일 for 루프
for ((i = 0; i < 5; i++)); do
  echo "$i"
done

# 파일 목록 순회 (ls 사용은 권장하지 않음)
for file in *.txt; do
  echo "$file"
done

# find와 함께 사용 (더 안전한 방법)
find . -name "*.txt" -print0 | while IFS= read -r -d $'\0' file; do
    echo "$file"
done

13.2. while 루프

count=0
while [ $count -lt 5 ]; do
  echo "$count"
  ((count++))  # 산술 연산
done

13.3. until 루프

count=5
until [ $count -le 0 ]; do
  echo "$count"
  ((count--))
done

14. 조건문 (Conditional Statements)

if [ "$str1" = "$str2" ]; then
  echo "문자열이 같습니다."
elif [ "$str1" = "$str3" ]; then
  echo "문자열이 같습니다."
else
  echo "문자열이 다릅니다."
fi

# [[ ]] 사용 (더 많은 기능, 패턴 매칭 등)
if [[ "$str1" == a* ]]; then  # $str1이 'a'로 시작하는지 확인
  echo "Starts with a"
fi

# (( )) 사용 (산술 연산)
if (( num > 10 )); then
  echo "Number is greater than 10"
fi

# 다중 조건
if [ "$str1" = "$str2" ] && [ "$num1" -gt "$num2" ]; then
  echo "Both conditions are true"
fi

# [[ ]] 에서의 다중 조건 (더 깔끔)
if [[ "$str1" = "$str2" && $num1 -gt $num2 ]]; then
  echo "Both conditions are true"
fi

주의: 조건문 내에 실행 문장이 없으면 오류가 발생합니다. 빈 블록을 만들려면 : (null command)를 사용하세요.

if [ -z "$var" ]; then
   : # Do nothing
else
    echo "var is not empty"
fi

15. 선택문 (case Statement)

case "$variable" in
  pattern1)
    # pattern1과 일치할 때 실행할 명령어
    ;;
  pattern2 | pattern3)
    # pattern2 또는 pattern3과 일치할 때 실행할 명령어
    ;;
  *)  # 어떤 패턴과도 일치하지 않을 때 (default)
    # 기본 명령어
    ;;
esac
for str in HELLO WORLD hello world s start end etc; do
    case "$str" in
        hello|HELLO)
            echo "$str: Matches 'hello' (case-insensitive)"
            ;;
        wo*)
            echo "$str: Starts with 'wo'"
            ;;
        [sS]tart) # s 또는 S로 시작하는 start
            echo "$str : Matches 'start' (case-insensitive)"
            ;;
        e|end)
          echo "$str: Matches 'e' or 'end'"
          ;;
        *)  # Default case
            echo "$str: Other"
            ;;
    esac
done

설명:

  • case 문은 변수 값을 여러 패턴과 비교하여 일치하는 경우 해당 블록의 명령어를 실행합니다.
  • 각 패턴 블록은 ;;로 끝나야 합니다.
  • |를 사용하여 여러 패턴을 OR 조건으로 묶을 수 있습니다.
  • *는 모든 경우에 일치하는 와일드카드 패턴입니다 (default case).
  • 패턴에는 와일드카드(*, ?, [...])를 사용할 수 있습니다.
  • case문 비교는 대소문자를 구분합니다.

16. 디버깅 (Debugging)

스크립트 실행 중 발생하는 문제를 찾고 해결하는 과정입니다.

  • echo: 변수 값이나 특정 메시지를 출력하여 코드 실행 흐름을 추적합니다.
  • set -x (bash -x): 명령어 실행 전에 해당 명령어를 출력합니다.
  • set -v (bash -v): 명령어 실행 전에 코드를 그대로 출력합니다.
  • set -u: 선언되지 않은 변수를 사용하려고 할 때 오류 메시지를 출력하고 스크립트를 종료합니다.
  • set -e: 명령어가 실패(0이 아닌 종료 상태 반환)하면 스크립트를 즉시 종료합니다.
  • bash -n script.sh: 스크립트를 실행하지 않고 문법 오류만 검사합니다.
  • trap: 특정 시그널(signal)을 받았을 때 실행할 명령어를 지정합니다. (고급)
# 디버깅 예시
set -x  # 명령어 추적 활성화

my_var="Hello"
echo "Value: $my_var"

set +x  # 명령어 추적 비활성화

마무리

  • Bash는 공백에 민감합니다. 명령어, 변수, 연산자 사이의 공백을 정확하게 사용해야 합니다.
  • 변수를 사용할 때는 ${변수} 형태로 사용하는 것이 좋습니다. 특히 매개변수 확장을 사용할 때는 필수입니다.
  • [ ] (test) 보다 [[ ]] (확장 test)를 사용하는 것이 좋습니다. [[ ]]는 더 많은 기능(패턴 매칭, &&, || 연산자 등)을 제공하고, [ ]보다 덜 혼란스럽습니다.
  • 산술 연산은 $(( ))을 사용하는 것이 가독성이 좋습니다.

참고 자료

대화 참여하기

댓글 1개

  1. 문서 수정: 2015-01-27
    - 함수에서 인자값 넘기는 예제 코드 추가
    - 선택문(case) 추가