0️⃣ 들어가며

지난 편에 이어 Bash의 심화 기능을 다루는 글이다.
잘 알아 두면 매우 편리한 확장과 명령어 치환,
리다이렉션과 파이프라인에 대한 내용이다.
중요하지 않은 부분도 있고 많이 쓰는 부분도 있어서
익숙한 거 위주로 잘 보면 된다.


1️⃣ 학습 내용

11. Bash: 확장과 셸 옵션

✅ 확장

  • 확장(Expansion)

    셸이 명령어를 실행하기 전에 변수, 표현식 등을 실제 값으로 변환하는 자동 치환 과정

    # 확장 실행 순
    1. 중괄호 확장 {a,b}
    2. 틸데 확장 ~
    3. 변수 치환 $VAR
    4. 명령어 치환 $(cmd), `cmd`
    5. 산술 치환 $(( ))
    6. 와일드카드 *? 확장
    7. 공백 분리 (word splitting)
  • 중괄호 확장(Brace Expansion)

    중괄호 {}를 사용해 문자열 시퀀스나 조합을 자동 생성하는 것

    문자열은 쉼표로 구분하고 사이에 공백이나 쿼팅이 있으면 안 됨

    아스키 값을 토대로 확장하는 증분을 사용할 수 있음

    # 중괄호 확장 사용
    {item1,item2,item3}           # 쉼표 구분 리스트
    {start..end}                  # 범위 (숫자/문자)
    {start..end..step}            # 단계 포함 범위
    prefix{list}suffix            # 접두사/접미사
    # 기초 확장
    echo {a..z}
    a b c d e f g h i j k l m n o p q r s t u v w x y z
    
    # for문에서 활용
    for i in {1..3}; do echo "i is $i"; done
    i is 1
    i is 2
    i is 3
    
    # 파일명 일괄 생성
    touch backup-{2025{01..12},2024{01..12}}.tar.gz
    
    # 복합 패턴
    echo file-{1..3}-{A..C}.txt
    # file-1-A.txt file-1-B.txt file-1-C.txt ... file-3-C.txt
    
    # 중첩 확장
    echo {{A,B},{X,Y}}Z
    # AZ BZ XZ YZ
  • 틸데 확장(Tilde Expansion)

    ~를 홈 디렉토리로 자동 변환하는 기능

    ~           → 현재 사용자 홈 ($HOME)
    /home/username
    
    ~username   → 특정 사용자 홈
    ~otheruser  → /home/otheruser
    
    ~+          → 현재 디렉토리 ($PWD)
    ~-          → 이전 디렉토리 ($OLDPWD)

✅ 명령어 치환

  • 명령어 치환(Command Substitution)

    명령어를 실행하고 그 표준 출력(stdout)을 문자열로 만들어 현재 명령어나 변수에 사용하는 기능

    $(명령어) 또는 명령어 → 명령 실행 → 결과 문자열 반환

    $VAR     → 변수 치환 (값 가져오기)
    $(CMD)   → 명령어 치환 (명령 실행 → 결과 문자열)
    # 현대 표준
    DATE=$(date)
    # 백틱 사용(구식)
    DATE=`date`
    
    2025. 12. 01. () 09:35:58 KST # 결과 동일
    • 명령어 치환과 반환값의 구분

      항목명령어 치환 $( )반환값 return
      저장 방법VAR=$(함수)STATUS=$?
      반환 내용stdout 출력종료 코드 0-255
      용도계산 결과, 파일 목록 등성공/실패 여부
      용량 제한메모리 제한 없음0~255 바이트
      get_files() {
      		# 함수를 명령어 치환으로 호출하여 표준 출력(stdout)으로 출력한 내용
          ls *.txt
          # 반환값은 별도로 처리
          return 0
      }
      
      FILES=$(get_files)           # file1.txt file2.txt
      STATUS=$?                    # 0

✅ 산술 확장

  • 산술 확장(Arithmetic Expansion)

    정수로 된 수학 표현식을 연산하고 결과를 반환하는 기능

    $((표현식))     → 값 반환 (명령어 치환처럼 사용)
    ((표현식))      → 조건문/반복문 조건으로 사용 (값 반환 X)

    산술 확장을 사용하면 변수 앞 $ 생략 가능 (예: a+1 = $a+1)

    식 내부의 공백 허용 (예: (( a + b )) = ((a+b)))

    결과를 저장하려면 표현식 안에서 변수의 값을 저장해야 함

  • 정수형 변수

    declare -i 로 선언한 변수

    정수형 변수는 산술 연산을 바로 적용할 수 있고, 정수가 아닌 값을 저장하면 0으로 처리

    정수형 → 일반변수: 정수값만 저장 (속성 사라짐)
    일반변수 → 정수형: 자동 변환 (연산 적용)
    declare -i num1=10
    declare -i num2="abc"     # "abc" → 0으로 변환
    echo $num1 $num2          # 10 0
    
    num1=$((num1 + num2))     # 자동 산술 연산
    echo $num1                # 10
  • 산술 연산자

    연산자의미예시
    +덧셈$((5 + 3))→8
    -뺄셈$((5 - 3))→2
    *곱셈$((5 * 3))→15
    /나눗셈 (몫)$((7 / 2))→3
    %나머지$((7 % 2))→1
    **거듭제곱$((2 ** 3))→8
    연산자의미예시
    var++후증가i=5; echo $((i++))→5(i=6)
    ++var전증가i=5; echo $((++i))→6(i=6)
    var--후감소i=5; echo $((i--))→5(i=4)
    --var전감소i=5; echo $((--i))→4(i=4)
    #!/bin/bash
    point="$1"
    
    if ((point >= 90)); then
        grade="A"
    elif ((point >= 80)); then
        grade="B"
    elif ((point >= 70)); then
        grade="C"
    elif ((point >= 60)); then
        grade="D"
    else
        grade="F"
    fi
    
    echo "Your grade is ${grade}"
    
    # bash grade.sh 100    # Your grade is A
    # bash grade.sh 80     # Your grade is B
  • 비교 연산자

    연산자의미
    ==같음
    !=다름
    <작음
    >
    <=작거나 같음
    >=크거나 같음
  • 논리 연산자

    연산자의미
    &&논리 AND
    !논리 NOT
  • 비트 연산자

    10진수를 2진수로 변환한 뒤 각 비트에 대해 연산을 수행

    연산자의미예시
    비트 OR
    &비트 AND$((5 \& 12))→4
    ^비트 XOR$((5 ^ 12))→9
    ~비트 반전$((~5))→-6
    <<왼쪽 시프트$((5 << 1))→10
    >>오른쪽 시프트$((12 >> 1))→6
    a=5
    b=12
    echo $((a | b))   # 13
    echo $((a & b))   # 4
    echo $((~a & b))  # 8
    echo $((a << 1))  # 10
    PERMISSIONS=644          # rw-r--r--
    EXECUTE=1                # ---x
    ((PERMISSIONS |= EXECUTE << 3))  # rwxr--r--
    echo "decimal: $PERMISSIONS"     # 755
    echo "octal: $((8#${PERMISSIONS}))"  # 755
  • 할당 연산자

    변수에 값을 저장하는 연산자

    연산자의미예시
    =대입a=5
    +=덧셈 대입((a += 3))
    -=뺄셈 대입((a -= 2))
    *=곱셈 대입((a *= 4))
    /=나눗셈 대입((a /= 2))

✅ 서브스트링 확장

  • 서브스트링 확장(Substring expansion)

    변수에 저장된 문자열의 특정 부분을 추출하는 Bash 파라미터 확장 기능

    오프셋 : 양수는 문자열 시작(0)부터, 음수는 문자열 끝(-1)부터

    음수 오프셋은 숫자 앞 공백 필수 (${VAR: -3})

    ${변수:오프셋}           # 오프셋부터 문자열 끝까지 추출
    ${변수:오프셋:길이}      # 오프셋부터 지정 길이만큼 추
    # 원본 문자열
    FILENAME="backup-2025-12-01.tar.gz"
    VERSION="v1.2.3"
    
    # 오프셋만 지정
    echo ${FILENAME:7}          # 2025-12-01.tar.gz
    
    # 오프셋과 길이 지정
    echo ${FILENAME:0:6}        # backup
    echo ${FILENAME:7:10}       # 2025-12-01
    
    # 음수 오프셋 (끝에서 시작)
    echo ${FILENAME: -7}        # tar.gz (끝 7자)
    echo ${VERSION: -2}         # 3 (끝 2자)

✅ 패턴 찾아 바꾸기

  • 패턴 찾아 바꾸기

    변수에 저장된 문자열 내에서 특정 패턴을 찾아 다른 문자열로 변경하는 기능

    형식설명예시 (foofoobar)결과
    ${변수/패턴/문자열}처음 일치하는 패턴만 한 번 바꿈${str/foo/bar}barfoobar(첫 번째foo만bar로)
    ${변수//패턴/문자열}모든 일치하는 패턴 바꿈${str//foo/bar}barbarbar(모든foobar로)
    ${변수/#패턴/문자열}문자열 시작 부분이 패턴과 일치하면 바꿈${str/#foo/bar}barfoobar(foo로 시작하면 변경)
    ${변수/%패턴/문자열}문자열 끝 부분이 패턴과 일치하면 바꿈${str/%bar/baz}foobar baz(bar로 끝나면 변경)

✅ 변수 값에 따른 확장

  • 변수 값에 따른 확장

    변수의 설정 여부와 내용에 따라 다른 값을 반환하거나 에러를 발생시키는 Bash 파라미터 확장 기능

    형식동작예시 (unset VAR)예시 (VAR="")예시 (VAR="set")
    ${VAR:-기본값}빈 값일 때 기본값 사용(변수 미설정)기본값기본값set
    ${VAR:=기본값}빈 값일 때 기본값 사용+ 변수에 저장기본값 (VAR=기본값)기본값 (VAR=기본값)set
    ${VAR:?에러메시지}빈 값일 때 에러 발생에러 종료에러 종료set

✅ 간접 확장, 일치하는 패턴 제거, 확장 연산자, 대소문자 바꾸기

생략

11.2 셸 옵션

  • 셸 옵션

    Bash의 동작 방식을 제어하는 설정값으로, set 명령어를 통해 변경 가능

    - : 옵션 활성화

    + : 옵션 비활성화

  • 주요 셸 옵션 목록

    옵션플래그설명
    errexit-E함수 내 trap 상속
    pipefail-o pipefail파이프라인에서 첫 실패 반환
    nounset-u미설정 변수 참조 시 에러
    xtrace-x명령 실행 전 추적 출력
  • set

    set -o 옵션명          # 활성화
    set -플래그            # 활성화 (예: set -x)
    set +o 옵션명          # 비활성화
    set +플래그            # 비활성화 (예: set +x)

12. Bash: 리다이렉션과 파이프라인

12.1 리다이렉션

✅ 리다이렉션

  • 리다이렉션(Redirection)

    표준 입출력 스트림의 방향을 변경하여 다른 스트림으로 입출력을 지정하는 기능

    스트림 번호이름기본 위치용도
    0stdin키보드입력
    1stdout터미널일반 출력
    2stderr터미널에러 출력
  • 출력 리다이렉션

    프로세스의 출력 스트림(표준 출력, 표준 에러)을 파일로 출력하는 것

    스트림 번호를 생략하면 표준 출력(1)이 자동으로 설정되고, 표준 에러는 2로 표기

    명령 [스트림_번호] > 파일  # 저장할 내용을 파일에 덮어쓰기
    명령 [스트림_번호] >> 파일 # 기존의 파일 내용에 이어 쓰기
    # 에러 리다이렉션
    username@host:~$ cc                  # 담을 내용 (에러)
    cc: fatal error: no input files
    compilation terminated.
    
    username@host:~$ cc 2> err           # stderr만 파일로
    username@host:~$ cat err
    cc: fatal error: no input files
    compilation terminated.
    
    username@host:~$ cc 2> /dev/stdout   # stderr → stdout으로 리다이렉트
    cc: fatal error: no input files
    compilation terminated.
  • 표준 출력과 표준 에러 한번에 리다이렉션

    명령 [스트림_번호] > 파일 [n]>&[m] : 스트림 n을 스트림 m으로 리다이렉션

    명령어의 실행 성공 여부를 알 수 없지만 한 파일에 리다이렉션하고 싶을 때 활용

    Bash는 표준 출력과 표준 에러를 동시에 리다이렉션하는 >& 기능을 제공

    username@host:~$ ping -c www.google.com > err 2>&1
    username@host:~$ ping -c www.google.com &> err # 동일하게 동작
    username@host:~$ cat err
    ping: invalid argument: 'www.google.com'
  • 입력 리다이렉션

    표준 입력을 키보드 대신 다른 파일 등의 스트림으로부터 받도록 하는 기능

    username@host:~$ cat < input.txt # 파일 내용 전체 출력
    username@host:~$ sort < names.txt # 정렬
    username@host:~$ wc -l < log.txt # 단어 수 세기

✅ Here documents / Here strings

  • Here documents

    임시 파일을 만들지 않고 여러 줄의 텍스트를 명령어의 표준 입력으로 전달하는 입력 리다이렉션

    구분자는 영문 한 단어로, 어떤 값이든 사용할 수 있으나 대부분 EOF/END를 사용

    파일 생성과 삭제가 불필요하고 권한 문제가 없으며, 파이프라인과 호환성 좋음

    명령어 [스트림_번호]<< 구분자
    [여러 줄 텍스트]
    구분자(동일한 문자열, 들여쓰기 없음)
    # 입력한 내용 바로 파일에 저장 가능
    cat << EOF > config.txt
    SERVER=localhost
    PORT=8080
    DEBUG=true
    DATABASE=/var/db/app.db
    EOF
  • Here strings

    Here documents와 유사하지만 텍스트 한 줄을 입력하는 기능

    명령어 [스트림_번호]<<< 문자열
    sort <<< "cherry
    banana
    apple" # 정렬
    
    wc -w <<< "Hello World Bash" # 단어 수 세기
    
    sed 's/Bash/Shell/g' <<< "Hello World Bash" # sed 치환

12.2 파이프라인

✅ 파이프라인의 개념과 사용법

  • 파이프라인(Pipeline)

    여러 프로세스의 입출력 스트림을 파일 없이 직접 연결하여 데이터를 전달하는 방식

    한 명령어의 출력을 다음 명령어의 입력으로 바로 전달하기 때문에 연속적인 데이터 처리 가능

    # 파이프라인 사용법
    command1 | command2 | command3
    
    # 표준 오류를 포함하여 전달하는 법
    command1 |& command2 |& command3
  • xargs

    표준 입력으로 받은 내용을 명령어의 인수로 변환하여 실행

    username@host:~$ touch err1 err2 err3
    username@host:~$ ls | grep err | xargs rm   # grep으로 걸러진 파일명을 xargs가 rm에 인수로 넘김
    username@host:~$ ls | grep err              # err로 시작하는 파일 없음
  • 파이프라인의 프로세스 종료 코드

    기본적으로 파이프라인 명령어의 종료 상태는 마지막 명령의 프로세스 종료 코드만 반영

    중간 명령어가 실패해도 알기 어려움

    • 중간에 실패하는 경우 종료 코드에 반영하기

      pipefail 옵션을 설정하면 파이프라인에 포함된 명령어 중 실패하는 명령이 있을 때 전체 실패 처리

      set -o pipefail
      command1 | command2 | command3

2️⃣ 느낀 점

처음에는 변수 확장과 명령어 치환이 조금 헷갈렸는데
쓰다 보니 편리하고 좋은 기능이라는 생각이 들었다.
확장은 워낙 방대한 부분이라 다 알 필요까지는 없고
필요할 때 찾아서 활용해 보면 좋겠다.

0개의 댓글