쉘 스크립트에서 변수는 별도의 선언(형식 지정) 없이 바로 사용할 수 있어 유연하지만, 그만큼 문법이 엄격한 부분도 있습니다.
특히 공백과 따옴표 사용법이 핵심입니다.
변수 선언과 사용 (Variables)
Shell 변수는 선언 시 타입을 지정하지 않으며, 공백에 매우 민감합니다.
# 선언: = 앞뒤 공백 금지 (필수!)
NAME="lycos7560"
COUNT=42
# 사용: $ 또는 ${}를 사용
echo "$NAME" # 일반적인 사용
echo "${NAME}" # 경계를 명확히 할 때 권장
echo "User_${NAME}_log" # 변수명 뒤에 문자가 붙을 때 필수
- ⚠️ 주의:
NAME = value처럼 공백을 넣으면 시스템은NAME을 변수가 아닌 명령어로 인식하여 에러(command not found)를 발생시킵니다
특수 변수 (Special Variables)
스크립트 실행 시 자동으로 할당되는 예약 변수들입니다.
| 변수 | 의미 | 예시 (./run.sh aix hacmp) |
$0 | 스크립트 이름 | ./run.sh |
$1 ~ $9 | 위치 매개변수 (인자) | $1은 aix, $2는 hacmp |
$# | 인자 개수 | 2 |
$@ | 모든 인자 (각각 분리) | "aix" "hacmp" |
$? | 마지막 명령어 종료 코드 | 0(성공) 또는 1~255(실패) |
$$ | 현재 프로세스 PID | 1234 |
기본값 처리 (Default Values)
변수가 비어있을 때를 대비한 방어적 코딩 기법입니다.
${VAR:-default}:VAR이 비어있으면default를 사용 (변수 값은 유지)${VAR:=default}:VAR이 비어있으면default를 변수에 대입${VAR:?message}:VAR이 비어있으면 메시지 출력 후 스크립트 종료
# 예시
HOST=""
printf "Connecting to %s...\n" "${HOST:-localhost}" # localhost 출력
패턴 제거 (Pattern Removal)
파일 경로에서 파일명만 추출하거나 확장자를 뗄 때 가장 많이 사용하는 강력한 기능입니다.
| 문법 | 설명 | 기억법 |
${VAR#패턴} | 앞에서부터 최단 일치 제거 | #은 키보드 왼쪽(앞), 하나는 짧게 |
${VAR##패턴} | 앞에서부터 최장 일치 제거 | ##은 길게 |
${VAR%패턴} | 뒤에서부터 최단 일치 제거 | %는 키보드 오른쪽(뒤), 하나는 짧게 |
${VAR%%패턴} | 뒤에서부터 최장 일치 제거 | %%는 길게 |
FILE="/var/log/syslog.tar.gz"
echo "${FILE##*/}" # syslog.tar.gz (경로 제거)
echo "${FILE%.*}" # /var/log/syslog.tar (최종 확장자 제거)
echo "${FILE%%.*}" # /var/log/syslog (모든 확장자 제거)
echo "${FILE%/*}" # /var/log (디렉토리만 추출)
[결과]
$ ./01_hello.sh start
syslog.tar.gz
/var/log/syslog.tar
/var/log/syslog
/var/log
문자열 치환 및 대소문자 변환 (Bash 확장)
주의: 아래 기능들은 Bash 4.0 이상에서 지원됩니다.
구형 AIX의 /bin/sh에서는 작동하지 않을 수 있으니 환경을 확인하세요.
문자열 치환
${STR/old/new}: 첫 번째 일치 항목만 치환${STR//old/new}: 모든 일치 항목 치환
대소문자 변환
${STR^^}: 전체 대문자${STR,,}: 전체 소문자
문자열 분리 (IFS 활용)
IFS(Internal Field Separator)는 쉘이 단어를 나누는 기준 문자입니다.
이를 변경하여 CSV 형태의 데이터를 쉽게 분리할 수 있습니다.
# 콜론(:)으로 구분된 데이터 파싱 LINE="hostname:192.168.1.1:8080" IFS=":" read -r HOST IP PORT << EOF $LINE EOF printf "Host: %s, IP: %s, Port: %s\n" "$HOST" "$IP" "$PORT"
POSIX 표준 변수 처리(${#}, ${%})는 매우 빠르고 효율적입니다.
sed나 awk 같은 외부 명령어를 호출하지 않고도 쉘 자체 기능만으로 문자열을 처리하는 습관을 들이면 스크립트의 성능이 비약적으로 향상됩니다!
00_Test.sh
#!/bin/sh
echo "\$0 = $0 → 현재 스크립트의 이름"
echo "\$1 = $1 → 첫 번째 인자"
echo "\${10} = ${10} → 열 번째 인자 (\$10 이상은 \${}로 감싸야 함)"
echo "\$# = $# → 전달된 인자의 개수"
echo "\$* = $* → 모든 인자 (하나의 문자열)"
echo "\$@ = $@ → 모든 인자 (각각 분리)"
echo "\$\$ = $$ → 현재 스크립트의 프로세스 ID"
echo "\$? = $? → 마지막 명령어 종료 상태 (0=성공)"
echo "\! = $! → 마지막 백그라운드 명령어의 PID"
echo "\$_ = $_ → 마지막 인자 또는 명령어"
echo "\$- = $- → 현재 셸 옵션"
$ sh 00_Test.sh 1 2 3 4 5 6 7 8 9 10 11 12
$0 = 00_Test.sh → 현재 스크립트의 이름
$1 = 1 → 첫 번째 인자
${10} = 10 → 열 번째 인자 ($10 이상은 ${}로 감싸야 함)
$# = 12 → 전달된 인자의 개수
$* = 1 2 3 4 5 6 7 8 9 10 11 12 → 모든 인자 (하나의 문자열)
$@ = 1 2 3 4 5 6 7 8 9 10 11 12 → 모든 인자 (각각 분리)
$$ = 8455 → 현재 스크립트의 프로세스 ID
$? = 0 → 마지막 명령어 종료 상태 (0=성공)
\! = → 마지막 백그라운드 명령어의 PID
$_ = \! = → 마지막 백그라운드 명령어의 PID → 마지막 인자 또는 명령어
#!/bin/sh
# ./test.sh "AIX 6.1" "HACMP cluster" "node1"
echo "=== 인자 개수: $# ==="
echo ""
echo "--- \"\$*\" 사용 ---"
i=1
for arg in "$*"; do
echo " [$i] $arg"
i=$((i+1))
done
echo ""
echo "--- \"\$@\" 사용 ---"
i=1
for arg in "$@"; do
echo " [$i] $arg"
i=$((i+1))
done
$ sh 00_Test.sh 1 2 3 4 5 6 7 8 9 10 11
=== 인자 개수: 11 ===
--- "$*" 사용 ---
[1] 1 2 3 4 5 6 7 8 9 10 11
--- "$@" 사용 ---
[1] 1
[2] 2
[3] 3
[4] 4
[5] 5
[6] 6
[7] 7
[8] 8
[9] 9
[10] 10
[11] 11


