codingstairs
노트에듀라이프연락
⌕검색⌘K
koen

Navigation

  • Intro
  • Blog
  • Life

연락하기

로그인 없이도 보낼 수 있어요. 답변이 필요하면 이메일을 함께 적어 주세요.

  • 익명 폼으로 의견 남기기 →
  • ✉ warragon112@gmail.com
  • 카카오톡 오픈채팅 ↗

© 2026 codingstairs

  • 노트
  • 에듀
  • 검색
  • 라이프
  • 연락
  • 약관
  • RSS
  • GitHub
노트›environment

sh 와 bash

2026-04-28 게시· 2026-05-18 갱신·0회 조회

sh 와 bash

Unix 계열 시스템에서 가장 자주 만나는 셸은 bash 입니다. 그리고 그 뿌리에는 sh (Bourne shell) 가 있습니다.

1. sh 와 bash 의 관계

  • sh (Bourne shell) — Stephen Bourne 이 1977 년 Unix V7 을 위해 만든 셸. 이후 POSIX 가 표준화한 sh 의 기준.
  • bash (Bourne Again Shell) — Brian Fox 가 1989 년 GNU 프로젝트로 만든 sh 호환 셸. POSIX sh 의 상위 집합으로, 배열·연관 배열·[[ ]] 같은 확장.

/bin/sh 는 시스템마다 가리키는 실체가 다릅니다. 일부 Linux 배포판은 dash (가벼운 POSIX sh) 로, 다른 배포판은 bash 의 sh 호환 모드로 연결. macOS 는 /bin/sh 가 bash 의 sh 모드.

같은 스크립트라도 #!/bin/sh 로 시작하면 POSIX 범위만 허용되고, #!/bin/bash 또는 #!/usr/bin/env bash 로 시작하면 bash 확장을 쓸 수 있습니다.

2. shebang 과 실행 권한

스크립트 파일의 첫 줄 #! 는 shebang. 커널은 실행 시 이 줄을 보고 어떤 인터프리터로 파일을 돌릴지 결정합니다.

#!/usr/bin/env bash
echo "hello"

/usr/bin/env bash 형태는 bash 의 절대 경로가 시스템마다 다를 때 (/bin/bash vs /usr/local/bin/bash) 유연하게 찾아 실행해 줍니다.

작업 macOS · Linux Windows (Git Bash · WSL)
권한 부여 chmod +x script.sh (WSL · Git Bash 안에서 동일)
실행 ./script.sh ./script.sh 또는 bash script.sh
직접 인터프리터 호출 bash script.sh bash script.sh

bash script.sh 처럼 인터프리터를 직접 부르면 실행 비트가 없어도 동작.

3. 변수와 조건문

NAME="world"
echo "hello, $NAME"
echo "hello, ${NAME}!"

= 양옆에 공백을 두면 안 됩니다. NAME = "world" 는 명령 실행으로 해석되어 에러.

if [ -f config.json ]; then
  echo "found"
elif [ -d config ]; then
  echo "directory"
else
  echo "not found"
fi

bash 에서는 [[ ... ]] 도 가능. [[ ]] 는 단어 분리·글로빙을 하지 않아 안전하지만 POSIX sh 에는 없습니다.

if [[ "$NAME" == "world" ]]; then
  echo "match"
fi

4. 반복과 함수

for f in *.txt; do
  echo "$f"
done

i=0
while [ $i -lt 5 ]; do
  echo $i
  i=$((i + 1))
done
greet() {
  local name="$1"
  echo "hello, $name"
}
greet "alice"

local 은 bash 확장이며 POSIX sh 에는 없습니다. POSIX 범위에서는 모든 변수가 전역.

5. 파이프와 리다이렉션

ls -la | grep "\.md$"          # 표준출력을 다음 명령으로
echo "log entry" >> app.log    # append
command 2> errors.txt          # 표준에러 리다이렉션
command > out.txt 2>&1         # 둘 다 한 곳으로
command 2>/dev/null            # 에러 버리기

6. set -euo pipefail

스크립트 첫머리에 자주 등장하는 한 줄.

옵션 의미
-e 명령이 비-0 으로 종료되면 즉시 스크립트 종료.
-u 정의되지 않은 변수를 참조하면 에러.
-o pipefail 파이프 내 어느 단계라도 실패하면 전체 실패.

이 셋이 없으면 중간 명령이 실패해도 스크립트가 계속 진행되어 망가진 상태로 끝나기 쉽습니다. 다만 -e 는 일부 합법적인 비-0 반환 (예: grep 이 매칭 없을 때 1) 을 에러로 잡으므로, 그 부분은 || true 로 명시 처리.

#!/usr/bin/env bash
set -euo pipefail

count=$(grep -c "ERROR" app.log || true)
echo "errors: $count"

7. dash vs bash 비호환 함정

Debian · Ubuntu 의 /bin/sh 가 dash 인 점은 자주 문제가 됩니다. bash 에서 잘 돌던 스크립트가 dash 에서 깨지는 대표 사례:

  • [[ ... ]] 는 dash 에 없음. [ ... ] 만.
  • 배열 (arr=(a b c)) 은 dash 에 없음.
  • function name() { } 의 function 키워드는 dash 에 없음. name() { } 만.
  • <<< (here-string) 은 dash 에 없음.
  • == 비교는 POSIX 가 아님. = 만 안전.
  • local 은 dash 에 있긴 하나 POSIX 표준은 아님.

스크립트가 bash 확장을 쓰면 shebang 을 #!/usr/bin/env bash 로 분명히. POSIX 범위에 머물 의도라면 #!/bin/sh 로 적고 dash 에서 한 번 검증.

8. 양 환경에서의 호출

# macOS · Linux
#!/usr/bin/env bash
set -euo pipefail
chmod +x deploy.sh
./deploy.sh
# Windows (Git Bash · WSL)
bash deploy.sh
# 또는 WSL
wsl bash deploy.sh

cmd.exe 나 PowerShell 에서 직접 .sh 를 더블클릭하거나 호출하면 동작하지 않습니다. 셸 자체가 bash 가 아니기 때문.

9. 자주 걸리는 자리

변수 인용 빠뜨리기 — rm $FILE 에서 $FILE 이 비어 있으면 rm 만 실행되어 에러로 끝나지만, 공백이 들어 있으면 의도하지 않은 파일을 지움. 항상 "$FILE" 로 인용.

== vs = — [[ ]] 안에서는 둘 다 동작하지만 [ ] 에서는 = 만 POSIX.

수치 비교에 > · < 사용 — [ $a > $b ] 는 비교가 아니라 리다이렉션. -gt · -lt 를 사용.

윈도우 줄바꿈 (CRLF) 으로 저장된 .sh 가 \r 때문에 실행 실패 — dos2unix 또는 git 의 text eol=lf 설정.

set -e 를 쓴 상태에서 command || true 를 빠뜨려 의도와 다르게 종료.

하고픈 말

shebang + set -euo pipefail + 변수 인용 + eol=lf 네 자리가 정착된 스크립트는 OS 차이를 거의 안 드러냅니다. 깐깐한 dash 환경에서 한 번 돌려 보면 호환성 사고를 미리 잡을 수 있어요. ShellCheck 도 좋은 출발점.

Next

  • powershell-basics
  • cmd-and-bat

GNU Bash Reference Manual · POSIX Shell · BashGuide · ShellCheck · Dash 매뉴얼 을 참고합니다.

environment 카테고리의 다른 글

카테고리 전체 보기 →
  • WSL2 — Windows 위의 Linux
  • 데이터 포맷 — JSON · YAML · TOML · XML
  • 터미널 첫날
  • 텍스트 인코딩과 줄바꿈
  • Markdown
  • 크로스 플랫폼 스크립트