심심한 개발자의 취미생활

Shell Script 기초 문법 정리

기본 구조

  • Shebang
    • #! 스크립트의 가장 첫 줄에 작성하며, 이 스크립트를 실행할 인터프리터를 지정한다.
  • 주석
    • # 기호 뒤에 오는 모든 내용은 주석으로 처리되어 실행되지 않는다.
#!/bin/bash     # Shebang 

# 주석
echo "Hello shell script world"

변수 관리

변수

  • 선언 및 할당
    • = 기호를 사용하며, 기호 앞뒤에 공백이 없어야 한다.
  • 사용
    • 변수 이름 앞에 $ 를 붙여 사용한다. 문자열고 함께 사용할 때는 중괄호 {}로 감싸는 것이 안전한다.
name="ballboy"
echo "Hello $name"
echo "Hello ${name}!"

매개변수

  • 스크립트나 함수에 전달된 인자를 참조한다.
    매개변수 설명
    $0 스크립트(또는 쉘)의 이름
    $1, $2, ... 첫 번째, 두번째, ... 인자
    $# 전달된 총 인자의 개수
    $@ 모든 인자를 각각의 문자열로 취급 ("$1", "$2", ...)
    $* 모든 인자를 하나의 문자열로 취급 ("$1 $2 $3 ...")
    $? 마지막으로 실행된 명령어의 종료 코드 (0은 성공, 0이 아니면 실패)
# 스크립트 이름 : script.sh
# 싫행 : script.sh arg1 arg2 arg3

echo "스크립트 이름: $0"
echo "첫 번째 인자: $1"
echo "인자 개수: $#"
echo "모든 인자: $@"

입력

  • 사용자로부터 입력을 받아 변수에 저장한다.
read user_name
echo "${user_name}"

연산

산술 연산 (정수)

  • 이중 소괄호(())를 사용 산술 연산을 수행하며 괄호 안의 변수에는 $를 붙이지 않는다.
  • 프로그래밍 언어와 유사한 연산자를 사용한다.(+, -, *, /, %, ++, --, += 등)
  • 그 외 let, expr 명령어를 사용하여 산술 연산을 수행할 수 있으나 최근에는 잘 사용되지 않는다.
a=5
b=3
sum=$((a + b))
echo "$sum"

산술 연산 (소수점)

  • 쉘의 기본 산술 연산은 정수만 지원한다. 소스점 계산이 필요할 때는 bc(Basic Calculator) 명령어를 사용해야 한다.
result=$(echo "10 / 3" | bc)
echo "$result" # 출력 : 3 (기본적으로 정수 나눗셈)

result=$(echo "scale=4; 10 / 3" | bc)
echo "$result" # 출력 : 3.3333 (scale 변수로 소스점 자릿수 지정)

a=5.5
b=2.2
result=$(echo "$a + $b" | bc)
echo "$result" # 출력 : 7.7

문자열 조합

  • 변수나 문자열을 단순히 나열하여 붙일 수 있다.
  • 변수 이름 뒤에 다른 문자가 바로 이어져 변수 이름의 경계가 모호해질 수 있으므로 중괄호{}로 감싸주어야 한다.
str1="Hello"
str2="ballboy"

result="${str1}, ${str2}!"
echo $result
echo "${str1}, ${str2}'s world'"

message="Hello"
message+=", "
message+="world!"
echo ${message} # 출력 : Hello, world!

문자열 길이

  • 문자열의 길이는 변수명 앞에 #를 붙인다.
str="abcdef"
echo "length : ${#str}" # 출력 : length : 5

문자열 자르기

  • 기본 형태 : ${변수명:시작위치:길이}
  • 시작 위지는 0부터 이다.
str="Hello, world"
sub_str=${str:7:5}
echo $sub_str # 출력 : world

문자열 치환

  • 기본 형태
    • 처음 일치하는 하나만 변경 : ${변수명/찾을패턴/바꿀문자열}
    • 일치하는 모든 패턴을 변경 : ${변수명//찾을패턴/바꿀문자열}
path="/home/user/documents/file.txt"

# 처음 'user'를 'guest'로 변경
new_path=${path/user/geust}
echo $new_path # 출력 : /home/guest/documents/file.txt
# 모든 '/'을 '-'로 변경
dashed_path=${path//\//-}
echo $dashed_path # 출력 : -home-user-documents-file.txt

문법

연산자

  • 산술 비교

    연산자 설명 예시
    -eq 같음 (equal) [ "$a" -eq "$b" ]
    -ne 다름 (not equal) [ "$a" -ne "$b" ]
    -gt 초과 (greater than) [ "$a" -gt "$b" ]
    -lt 미만 (less than) [ "$a" -lt "$b" ]
    -ge 크거나 같음 (greater or equal) [ "$a" -ge "$b" ]
    -le 작거나 같음 (less or equal) [ "$a" -le "$b" ]
  • 문자열 비교

    연산자 설명 예시
    == or = 두 문자열이 같음 [ "$a" == "$b" ]
    != 두 문자열이 다름 [ "$a" != "$b" ]
    -z 문자열이 비어있음 [ -z "$a" ]
    -n 문자열이 비어있지 않음 [ -n "$a" ]
  • 파일 조건

    연산자 설명 예시
    -f 파일이 존재하고 일반 파일임 [ -f "file.txt" ]
    -d 파일이 존재하고 디렉터리임 [ -d "dir" ]
    -e 파일 또는 디렉터리가 존재함 [ -e "some/path" ]
    -s 파일이 존재하고 크기가 0보다 큼 [ -s "file.txt" ]

조건문

  • 조건식은 대괄호 []또는 이중 대괄호 [[]]안에 작성하며, 각 요소 사이에 공백이 필수이다.
if [ 조건 ]; then
  # 참일 때
elif [ 조건 ]; then
  # 다른 조건
else
  # 거짓일 때
fi
# 숫자 비교
if [ "$a" -eq "$b" ]; then
# 문자열 비교
if [ "$str1" = "$str2" ]; then
# 파일 존재 여부
if [ -f "file.txt" ]; then

반복문

  • for 문
    • 목록의 각 항목에 대해 명령을 반복 실행한다.
# List-based for loop
for i in "apple" "banana" "cherry"; do
    echo "Fruit: $i"
done

# C-style for loop
for (( i=0; i<5; i++ )); do
    echo "Number: $i"
done
  • while 문
    • 조건이 참인 동안 명령을 반복 실행한다.
count=0
while [ $count -le 5 ]; do
    echo "Count: $count"
    count=$((count + 1))
done

함수

  • 재사용이 가능한 코드 블록을 정의한다.
# 방법 1 (일반적)
greet1() {
    echo "greet1 - Hello, $1"
}

# 방법 2 
function greet2() {
    echo "greet2 - Hello, $1"
}

# 함수 호출
greet1 "Ballboy"    # 출력 : greet1 - Hello, Ballboy
greet2 "Franciscus" # 출력 : greet2 - Hello, Franciscus

유용한 기능

명령어 치환

  • 명령어의 실행 결과를 변수에 저장하거나 다른 명령어의 인자로 사용
  • 백틱`도 사용 가능하지만, $() 사용이 권장됨
current_date=$(date +%Y-%m-%d)
echo "Today is ${current_date}"

FILE_LIST=`ls`

입출력 리다이렉션

  • > : 표준 출력을 파일로 리다이렉션 (덮어쓰기)

    • ls -l > file_list.txt
      • ls -l의 결과를 file_list.txt에 덮어씀
  • >> : 표준 출력을 파일로 리다이렉션 (이어쓰기)

    • echo "New line" >> file_list.txt
      • 파일 끝에 내용 추가
  • < : 파일의 내용을 표준 입력으로 사용

    • sort < file_list.txt
      • 파일을 정렬하여 출력
  • | : 한 명령어의 출력을 다른 명령어의 입력으로 연결 (파이프)

    • ls -l | grep ".txt"
      • ls 결과 중 .txt를 포함하는 라인만 필터링

Exit & 에러 처리

  • exit 명령어는 스크립트를 즉시 종료시키는 데 사용된다. 이 때, 스크립트 전체의 종료 상태를 직접 지정할 수 있다.
    • 0: 성공
      • 명령어가 문제 없이 정상 적으로 실행되었음
    • 1 ~ 255: 실패
      • 어떠한 이유로든 명령어 정상 실행 실패
exit 0
exit 1

command || echo "에러 발생"
command && echo "성공"
  • 에러 감지 특수 변수 : $?
    • $?는 바로 직전에 실행된 명령어의 종료 상태를 담고 있는 변수
# 정상 실행 명령어
ls /
echo "$?"  # 출력: 0

# 실행 실패 명령어 (존해하지 않는 파일/디렉토리)
ls /non_existent_dir
echo "$?" # 출력: 0이 아닌 값 (보통 1 or 2)
  • 자동 에러 처리 set 명령어
    • set 명령어를 스크립트 상단에 선언하면 스크립트의 동작 방식을 더 안전하게 바꿀 수 있다.
      • -e : 명령어가 0이 아닌 종료 상태를 반환하면 즉시 스크립트 실행을 중단
      • -u : 선언 되지 않은 변수를 사용하려고 할 때 에러로 간주하고 스크립트를 중단, 변수 이름의 오타 등을 방지
      • -o pipefail : 파이프라인 |으로 연결된 명령어들 중 하나라도 실패하면 전체 파이프 라인을 실패로 간주
#!/bin/bash
set -euo pipefail