Bash란 무엇인가, 셸이란 무엇인가 — 스크립트를 쓰기 전에
이 글에서는 GNU Bash 매뉴얼 1.1 What is Bash?, 1.2 What is a shell?, 3.8 Shell Scripts를 따라 Bash의 정체, 셸의 이중 역할, 스크립트 실행 모델을 정리합니다.
이 글을 읽고 나면
Bash가 sh / ksh / csh / POSIX와 어떤 관계인지 설명할 수 있습니다.
셸이 “명령 인터프리터 + 프로그래밍 언어”라는 점을 구분할 수 있습니다.
대화형 셸과 스크립트(비대화형) 실행·shebang의 의미를 이해합니다.
Bash란 무엇인가?
Bash는 GNU 운영체제의 셸, 즉 명령어 언어 인터프리터입니다. 이름은 Bourne-Again SHell — 7th Edition Unix의 Bourne 셸(sh, Stephen Bourne)에 대한 말장난입니다.
Bash의 중요한 특징을 한눈에 정리하면 아래와 같습니다.
비교 대상 |
쉬운 설명 |
|---|---|
sh(기본 셸) |
Bash는 예전 셸인 sh랑 거의 비슷하게 쓸 수 있지만, 명령어를 쉽게 쓰거나 프로그램처럼 다룰 수 있는 기능이 더 많아요. |
ksh, csh(다른 유명 셸) |
ksh나 csh에서 편리했던 기능도 가져왔어요. 쉽게 말해 좋은 건 다 흡수했다고 보면 돼요. |
POSIX(표준) |
“POSIX”라는 표준 규칙을 지키려고 해요. 그래서 다른 시스템에서도 Bash 스크립트를 잘 쓸 수 있어요. |
이식성 |
리눅스, 맥, 윈도우 등 거의 모든 운영체제에서 쓸 수 있도록 만들어졌어요. |
실무에서 많이 하는 실수 중 하나는 스크립트 첫 줄(shebang)에 #!/bin/sh를 적어 두고, Bash에서만 동작하는 문법([[ ]], 배열, ${BASH_SOURCE} 등)을 함께 사용하는 거예요. 이렇게 하면 이 파일은 실제로 Bash 스크립트가 아니라, sh가 이해할 수 있는 파일이어야 해요. 만약 배포 환경에서 /bin/sh가 Bash가 아니라 dash 같은 다른 셸이라면, 스크립트가 바로 오류를 내고 멈춰버릴 수 있습니다.
셸이란 무엇인가?
Unix나 리눅스에서 "셸"은 단순히 명령어를 입력하는 도구가 아니라, 명령들을 모아 자동화하거나 새로운 동작을 만들어낼 수 있는 두 가지 얼굴을 가지고 있어요.
- 명령 인터프리터:
보통 터미널에 ls, grep, make와 같은 명령을 입력하면, 이 명령들을 받아 실행해주는 역할을 해요.
- 프로그래밍 언어:
그리고 이 셸은 변수, 분기(if), 반복(for/while), 함수 등을 지원해서, 여러 명령을 파일에 모아두면 하나의 새로운 명령처럼 쓸 수 있습니다.
즉, 스크립트 파일은 /bin에 있는 시스템 명령과 동등하게 취급되기도 해요.
셸은 본질적으로 “명령을 실행하는 매크로 프로세서”입니다.
사용자가 입력한 텍스트와 심볼(변수 등)을 확장해서 복잡한 동작을 만들어냅니다.
실무자가 꼭 알아야 할 셸의 개념
용어 |
설명 |
|---|---|
대화형(Interactive) |
직접 키보드로 명령을 입력하는 방식 |
비대화형(Non-interactive) |
파일이나 문자열에서 명령을 읽는 방식 (스크립트 실행) |
동기/비동기 실행 |
끝날 때까지 기다리는 명령 vs &로 백그라운드 실행 |
내장 명령(Builtin) |
cd, exec, break 등 셸이 내부적으로 제공 (외부 프로그램이 아님) |
대화형 전용 기능 |
job control, 줄 편집, history, alias 등 편의 UX 기능 |
한눈에 정리하는 Bash 셸의 두 얼굴
Bash 셸은 그 자체로 "명령 인터프리터"이자, "실제 프로그래밍 언어" 역할까지 함께 해요.
즉, 아래 두 가지 관점이 모두 중요합니다:
명령어 인터프리터:
사용자가 ls, cd, grep처럼 한 줄씩 입력한 명령을 읽고, 해석해 실행하는 도구입니다.스크립트 언어:
변수, 조건문, 반복문, 함수 등 프로그래밍 기능을 내장해서, 여러 명령을 모아놓으면 새롭게 "하나의 명령"처럼 만들 수 있습니다.
실제로 Bash는 sh, ksh, csh 같은 이전 셸의 장점을 물려받아, 현대 리눅스에서 표준처럼 쓰이며,
POSIX라는 규칙도 따르려 노력해요. 그래서 Bash로 짠 스크립트는 웬만한 유닉스 계열 시스템에서 거의 그대로 동작하지요.
Bash를 "명령어 실행의 매크로 프로세서이자, 파일로도 담아 쓸 수 있는 언어"라고 정리할 수 있어요.
아래 표는 현업에서 꼭 아는 것이 유용한 셸 개념을 성격별로 나눠 정리한 것입니다.
분류 |
주요 특징 및 예시 |
|---|---|
대화형 |
명령 프롬프트에서 직접 명령을 입력(터미널). 줄 편집, 히스토리 지원 |
비대화형 |
파일(.sh)에 명령 모아 자동 실행(스크립트). shebang(#!/usr/bin/env bash) 필수 |
내장 명령 |
Bash 자체 기능. 예) cd, exit, echo, exec 등 |
외부 명령 |
실제 실행 파일이나 프로그램. 예) /bin/ls, /usr/bin/grep |
동기/비동기 |
기본은 순차(동기)실행, 끝나지 않은 명령을 &로 백그라운드(비동기) |
확장/치환 |
변수($VAR), 명령치환($(…)), 산술($((…))) 등 |
실전에서는
스크립트(.sh) 파일 과
터미널 명령줄 이 모두 Bash 셸의 기능 위에 돌아가고 있다고 생각하시면 됩니다.
예시:
아래는 Bash가 비대화형(스크립트) 모드에서 "누가 나를 실행했는지", "내 버전은 뭔지" 등을 출력하는 실제 코드입니다.
Bash
#!/usr/bin/env bash echo "=== script identity ===" echo "\$0 = $0" echo "BASH_VERSION = ${BASH_VERSION:-<unset — not bash?>}" echo "shell PID = $$" case $- in *i*) echo "mode = interactive" ;; *) echo "mode = non-interactive" ;; esac
정리:
Bash의 본질은 "명령 처리 + 자동화 + 프로그래밍 언어"라는 점을 꼭 기억해두세요!
셸은 본질적으로 명령을 실행하는 매크로 프로세서 이다. 텍스트와 심볼을 확장해 더 큰 표현을 만든다.
Unix 셸은 두 가지 형태를 갖습니다.
명령 인터프리터 — GNU/Unix 유틸리티를 사용자에게 연결합니다.
프로그래밍 언어 — 그 유틸리티를 조합합니다. 명령을 담은 파일은 그 자체가 새 명령이 되고, /bin의 시스템 명령과 같은 지위 로 PATH에서 찾을 수 있습니다.
추가로 알아 둘 점입니다.
개념 |
의미 |
|---|---|
Interactive |
키보드에서 입력을 받음 |
Non-interactive |
파일이나 문자열에서 명령을 읽음 (일반 스크립트) |
동기 / 비동기 |
끝날 때까지 기다림 vs &로 병렬 |
Builtin |
셸 내부 명령. cd·exec·break처럼 셸 자신 을 바꿔야 해서 외부 프로그램으로 둘 수 없는 것들이 있음 |
대화형 전용 기능 |
job control, 줄 편집, history, alias — “언어”보다 UX |
셸의 힘(과 복잡성)은 대부분 내장된 프로그래밍 언어 에서 옵니다. 변수, 제어 흐름, quoting, 함수가 그 뼈대입니다. 이후 시리즈 글이 바로 이 뼈대를 매뉴얼 순서대로 깎아 갑니다.
셸 스크립트란 무엇인가 (매뉴얼 3.8)
셸 스크립트 는 셸 명령을 담은 텍스트 파일입니다.
Bash를 다음처럼 호출하면 (그리고 -c / -s가 아니면) Bash는 그 파일에서 명령을 읽고 실행한 뒤 종료합니다. 이 모드가 비대화형 셸 입니다.
Bash
bash filename arguments…
실제 실행 과정을 단계별로 좀 더 상세하게 살펴볼게요.
항목 |
상세 동작 설명 |
|---|---|
$0 |
스크립트 파일 이름 이 저장됩니다. 즉, 내부적으로 bash filename arguments…로 실행하면 $0은 항상 "filename"으로 잡힙니다. 셸 자체 이름(bash)이 아니라, 사용자가 실행시키는 파일이 무엇인지 알려줍니다. |
위치 파라미터 ($1, $2, …) |
명령줄에서 넘긴 나머지 인자(argument) 들이 각각 $1, $2, …로 저장됩니다. 만약 인자를 주지 않았다면 해당 파라미터는 unset(설정 안 됨) 상태입니다. $#는 인자 개수를, $@/$*는 전체 인자 목록을 뜻합니다. |
경로에 /가 없음 |
실행 명령에 /가 없다면(예: myscript.sh), 우선 현재 디렉토리(./) 에서 해당 파일을 찾습니다. 여기서도 없을 경우에는 환경 변수 $PATH에 설정된 디렉토리들을 차례로 탐색합니다. 즉, 파일이 어디 있는지 알아서 찾아줍니다. |
실행할 파일이 바이너리로 보이면 |
스크립트 파일이 텍스트가 아니라 바이너리(실행파일)처럼 보일 경우, Bash는 해당 파일을 스크립트로 간주하지 않고 실행하지 않습니다. 즉, 명확히 텍스트 포맷(쉐뱅이나 명령)이 아니라면 에러를 냅니다. |
실제 동작은 다음과 같습니다.
사용자가 명령줄에 bash myscript.sh foo bar를 입력.
Bash는 myscript.sh 파일에서 위에서 설명한 방식으로 명령을 읽고 해석.
$0에는 myscript.sh, $1에는 foo, $2에는 bar가 셋팅.
만약 myscript.sh가 현재 폴더에 없으면, $PATH를 따라가며 탐색.
파일의 첫 부분이 실행 가능한 바이트코드/바이너리로 보이면, 명령 실행을 중단하고 에러를 표시.
이 동작 덕분에 스크립트 파일도 시스템 명령처럼 입력값·이름·인터프리터 동작 을 명확하게 분리해서 관리할 수 있습니다. 실전에서 $0와 위치 파라미터의 동작을 잘 이해하면, 스크립트의 재사용성과 안전성이 크게 높아집니다.
실행 비트를 켠 뒤 PATH에서 찾으면, 셸은 새 Bash 인스턴스 를 만들어 스크립트를 돌립니다. 즉 사용자가 입력한
Bash
filename arguments…
는 (해당 파일이 실행 가능한 셸 스크립트일 때) 사실상
Bash
bash filename arguments…
와 같습니다.
#! (shebang)
대부분의 Unix에서 스크립트 첫 줄이 #!로 시작하면, 그 뒤에 오는 인터프리터로 나머지 파일을 실행합니다.
Bash
#!/usr/bin/env bash
shebang |
의미 |
|---|---|
#!/bin/bash |
시스템 고정 경로의 bash |
#!/usr/bin/env bash |
$PATH에서 첫 bash (Homebrew 등) |
#!/bin/sh |
POSIX 셸로 해석될 수 있음 — Bash 전용 문법 금지 |
구형 Unix는 인터프리터 이름+인자를 32자로 자르는 경우가 있어, shebang에 인자를 여러 개 넣는 것은 이식성이 떨어집니다.
실행 예제
identify_shell.sh 스크립트는 "현재 실행 중인 것이 Bash 스크립트인지, 스크립트가 어떤 실행 모드(대화형/비대화형)로 동작 중인지"를 명확하게 보여줍니다. 실제로 아래와 같이 사용합니다.
Bash
chmod +x source/B-01-what-is-bash-shell/identify_shell.sh ./source/B-01-what-is-bash-shell/identify_shell.sh hello world
아래는 예제 스크립트 전체와 주요 라인별 설명입니다.
Bash
#!/usr/bin/env bash # B-01: identity of Bash / shell script vs interactive # Demonstrates shebang, $0, args, BASH_VERSION, interactive check. set -eu echo "=== script identity ===" echo "\$0 = $0" # (1) 현재 스크립트 이름 또는 경로를 출력합니다. echo "basename \$0 = $(basename -- "$0")" # (2) 스크립트 파일 이름만 추출합니다. echo "argc (\$#) = $# " # (3) 전달된 인자(argument) 개수 출력 if (($# > 0)); then printf 'args =' printf ' %q' "$@" # (4) 인자 목록을 안전하게 표시 printf '\n' fi echo echo "=== which Bash is running? ===" echo "BASH_VERSION = ${BASH_VERSION:-<unset — not bash?>}" # (5) Bash 버전 정보. unset이면 비Bash echo "BASH = ${BASH:-<unset>}" # (6) Bash 실행 경로 등 환경 정보 echo "shell PID \$\$ = $$" # (7) 현재 프로세스 ID echo echo "=== interactive? ===" # $- contains 'i' when the shell is interactive (manual: interactive shells) case $- in *i*) echo "mode = interactive" ;; # (8) $-에 i가 있으면 대화형 모드 *) echo "mode = non-interactive (typical for scripts)" ;; # (9) 그렇지 않으면 비대화형(스크립트) 모드 esac if [[ -n "${PS1-}" ]]; then echo "PS1 set = yes (often means interactive prompt)" # (10) PS1 프롬프트가 있으면 대화형 가능성 높음 else echo "PS1 set = no" # (11) 프롬프트 미설정 fi echo echo "ok — this file is a shell script (manual §3.8)."
주요 라인별 설명
1–3: 실행 시 스크립트의 이름($0)과 인자(argument) 개수/내용이 어떻게 잡히는지 확인합니다.
5–6: Bash 해석기로 실행되는지(BASH_VERSION, BASH 변수) 명확하게 보여줍니다.
8–9: $- 옵션 문자열에 'i'(interactive)가 있는지로 대화형 모드 판별.
10–11: PS1 환경변수 존재 여부로 프롬프트가 활성화된 대화형 쉘인지 추가로 진단합니다.
이 예제는 "같은 스크립트 텍스트라도 어떻게 실행(직접 실행/source 등)하느냐에 따라 셸의 모드와 변수 동작이 달라진다"는 점을 실감하라는 의도입니다. 대화형으로 이 스크립트를 source한다면 $-에 i가 포함될 수도 있습니다.
헷갈리기 쉬운 부분
macOS /bin/bash 3.2 — Linux CI의 Bash 5와 기능이 다릅니다. 스크립트 상단에서 BASH_VERSION을 확인하거나, shebang을 의도한 bash로 고정하세요.
로그인/대화형 설정 파일 — 스크립트는 보통 .bashrc를 읽지 않습니다. PATH·alias를 스크립트가 가정하면 cron/CI에서 실패합니다.
“터미널에서 되는 한 줄” ≠ 스크립트 — 대화형 편의(alias, history 확장)에 의존하지 마세요.
Bash가 답이 아닌 경우 — 복잡한 자료구조·HTTP·JSON 중심 로직은 Python 등이 유지보수에 유리합니다.
한 줄 요약
Bash는 POSIX 표준을 따르는 Bourne 계열의 셸이며, 셸은 명령을 해석하고 실행하는 인터프리터이자 자체 프로그래밍 언어입니다. 스크립트란 이러한 셸 언어로 작성된 비대화형 자동화 프로그램을 의미합니다.