지금까지 리눅스 셸 스크립팅(Linux Shell Scripting) 시리즈를 연재해 왔으며, 많은 독자분들의 뜨거운 호응을 받았고 지금도 여전히 유용한 내용으로 자리 잡고 있습니다. 아직 이전 글들을 읽지 않으셨다면 아래 링크에서 전체 시리즈를 확인해 보시기 바랍니다.
- 리눅스 셸 스크립팅 배우기
이번 글에서는 셸 스크립트의 핵심 요소인 변수(variable)에 대해 살펴보고, 변수의 실행 방식과 실제 구현 사례를 예제 중심으로 자세히 알아보겠습니다.
명령어 출력 결과 저장하기
명령어의 출력 결과는 표준 출력이나 파일로 리디렉션할 수 있을 뿐만 아니라, 변수에 저장하는 것도 가능합니다. 명령어의 출력량이 화면에 다 담기지 않을 만큼 방대하다면 파일이나 변수에 저장하는 것이 유일한 선택지가 됩니다.
출력 결과를 변수에 저장하면 무엇보다 조회 속도가 빠르다는 장점이 있습니다. 변수는 메모리에 저장되기 때문에 파일에서 데이터를 불러오는 것보다 훨씬 신속하게 처리됩니다.
셸 스크립트에서의 변수
변수는 셸 스크립팅에서 빼놓을 수 없는 핵심 구성 요소로, bash의 declare 명령어를 사용하여 선언합니다. 예를 들어 LEVEL이라는 변수를 선언하려면 아래 명령어를 실행하면 됩니다.
$ declare LEVEL
참고: Korn 셸과의 호환성을 위해서는 typecast라는 내장 문을 사용해야 합니다. 다만 declare가 더 발전된 형태로 모든 기능을 포함하고 있기 때문에, BASH 환경에서는 declare 사용을 권장합니다.
변수 선언 규칙
- 변수 이름은 해당 변수가 스크립트에서 수행하는 역할을 충분히 설명할 수 있어야 합니다.
- 프로그램 전체에서 동일한 변수 이름을 일관되게 사용하는 것이 좋습니다.
- 변수 이름은 대문자와 소문자 모두 사용할 수 있지만, 관례상 셸 명령어는 소문자로 작성되므로 혼동을 피하기 위해 변수 이름은 대문자로 작성하는 것이 좋습니다. 예: TOTAL_BILLED_AMOUNT, SELL_REPORT, ORDER_RECEIPT 등.
변수 구현하기
변수에는 등호(=)를 사용하여 값을 할당합니다. 변수에 빈 문자열을 할당하려면 등호 뒤에 아무 값도 입력하지 않으면 됩니다.
$ LEVEL=
변수 LEVEL에 저장된 값을 확인하려면 아래와 같이 입력합니다.
$ printf "%i" $LEVEL
printf는 C 언어 프로그래머라면 누구나 익숙한 명령어로, 데이터를 출력하는 역할을 합니다. %i는 정수(Integer)를 의미하며, 필요에 따라 문자는 %c, 문자열은 %s로 대체하여 사용할 수 있습니다.
$LEVEL에서 주목할 부분은 $ 기호입니다. 이 기호는 변수 LEVEL의 값으로 치환하는 역할을 합니다.
실행 결과 예시
$ printf "%i" $LEVEL 0
이번에는 변수에 직접 값을 할당해 보겠습니다.
$ LEVEL=0
저장된 값을 다시 확인합니다.
$ printf "%i" $LEVEL 0
주목: 흥미로운 점은 값을 할당하지 않은 경우와 값 0을 할당한 경우 모두 출력 결과가 0으로 동일하다는 것입니다. 하지만 출력이 같다고 해도 셸은 두 경우를 서로 다르게 처리한다는 점을 기억해야 합니다.
새로운 값을 할당해 보겠습니다.
$ LEVEL=121
저장된 값을 확인합니다.
$ printf "%i" $LEVEL 121
변수 해제하기(Unset)
declare는 BASH 명령어로, 실행되는 시점에 변수를 생성합니다. 이렇게 생성된 변수는 스크립트가 종료되거나 명시적으로 삭제될 때까지 메모리에 유지됩니다.
$ unset LEVEL
BASH에 미리 정의된 변수들
BASH에는 50개 이상의 변수가 미리 정의되어 있습니다. 이 중 일부는 BASH에서 특별한 의미를 갖습니다. 예를 들어 RANDOM 변수는 참조할 때마다 난수를 반환합니다. 만약 이러한 변수를 해제한 후 다시 정의하면 원래의 값은 영원히 사라집니다. 따라서 시스템이 정의한 변수를 임의로 사용하지 않는 것이 좋습니다.
아래는 실무에서 유용하게 쓰이는 대표적인 BASH 변수 목록입니다.
- BASH — Bash의 전체 경로명
- BASH_ENV — 셸 스크립트에서 스크립트 시작 전에 실행되는 프로파일 파일의 이름
- BASH_VERSION — Bash 버전 (예: 2.04.0(1)-release)
- COLUMNS — 화면의 한 줄당 문자 수 (예: 80)
- HOSTNAME — 컴퓨터 이름. 리눅스 버전에 따라 머신 이름일 수도 있고, 완전한 도메인 이름(FQDN)일 수도 있습니다.
- HOSTTYPE — 컴퓨터의 유형
- HOME — 홈 디렉터리의 이름
- OSTYPE — 운영체제의 이름
- PATH — 실행할 명령어를 찾기 위한 검색 경로 목록(콜론으로 구분)
- PPID — 셸의 부모 프로세스 ID
- PROMPT_COMMAND — PS1 기본 프롬프트 문자열이 설정되기 전에 실행되는 명령어
- PWD — 현재 작업 디렉터리(cd 명령어로 설정됨)
- RANDOM — 참조할 때마다 0부터 32767 사이의 난수를 반환
- SHELL — 프로그램이 셸을 시작할 때 사용하는 기본 셸
- TERM — 터미널 에뮬레이션 유형 (예: console)
단어 분할(Word Splitting) 규칙
아래 두 경우를 비교해 보겠습니다.
$ LEVEL=0 $ printf "%i" $LEVEL 0 그리고 $ LEVEL="0" $ printf "%i" $LEVEL 0
두 경우 모두 출력 결과가 동일합니다. 그렇다면 따옴표를 사용했을 때 결과에는 어떤 차이가 있을까요?
다른 데이터로 동일한 실험을 진행해 보겠습니다.
$ LEVEL=0 ; 1 ; 2 ; 3 ; 4 ; 5 bash: 1: command not found bash: 2: command not found bash: 3: command not found bash: 4: command not found bash: 5: command not found
$ printf "%i" $LEVEL 0
결과가 올바르지 않습니다. BASH는 0 뒤의 공백을 종료 지점으로 인식하여 변수 값을 0으로 설정해 버린 것입니다. 이번에는 변수에 따옴표를 적용해 보겠습니다.
$ LEVEL="0 ; 1 ; 2 ; 3 ; 4 ; 5" $ printf "%s" $LEVEL 0;1;2;3;4;5
여전히 결과가 올바르지 않습니다. BASH가 변수 값을 가져오면서 값 사이의 모든 공백을 제거해 버렸기 때문에, printf는 0,1,2,3,4,5를 서로 다른 개별 값으로 해석하지 못했습니다. 그렇다면 해결책은 무엇일까요?
printf "%s" "$LEVEL" 0 ; 1 ; 2 ; 3 ; 4 ; 5
네, 바로 변수 치환 전체를 따옴표로 묶는 것이 해결책입니다. 따옴표는 셸에서 문자들을 하나의 그룹으로 묶고 특수 문자를 의미 있는 방식으로 해석하도록 만듭니다.
따옴표는 연달아 사용할 수도 있으며, 변수 치환을 따옴표로 감싸는 것이 좋은 습관입니다. 또한 따옴표를 활용하면 전체 텍스트와 인용 구간을 분리할 수도 있습니다. 아래 예제를 살펴보겠습니다.
$ LEVEL=5 $ FLAG_MESSAGE="I HAVE CLEARED LEVEL""$LEVEL"". I Deserve appreciation." $ printf "%s" "$FLAG_MESSAGE"
"I HAVE CLEARED LEVEL5. I Deserve appreciation."
반면, 따옴표로 묶인 텍스트 조각들을 공백으로 구분하면 앞서 설명한 것과 같은 문제가 발생합니다. Bash는 공백을 종료 지점으로 처리하기 때문입니다. 변수 치환의 또 다른 방법은 아래와 같습니다.
$ LEVEL=5
$ FLAG_MESSAGE="I HAVE CLEARED LEVEL ${LEVEL}. I Deserve appreciation."
$ printf "%s" "$FLAG_MESSAGE"
"I HAVE CLEARED LEVEL 5. I Deserve appreciation."
한편, 작은따옴표(single quote)는 BASH가 특수 문자를 해석하지 못하도록 제한합니다.
$ printf "%s" '$FLAG_MESSAGE' "$FLAG_MESSAGE"
백슬래시(\) 활용하기
백슬래시는 단 한 글자에 대해서만 작은따옴표처럼 작동합니다. 그렇다면 큰따옴표(") 자체를 출력하려면 어떻게 해야 할까요?
$ printf "%c" "\""
printf와 함께 %q를 사용하면 각 단어 뒤에 백슬래시를 붙여 공백이 올바르게 유지되도록 출력할 수 있습니다.
$ LEVEL=5
$ FLAG_MESSAGE="I HAVE CLEARED LEVEL ${LEVEL}. I Deserve appreciation."
$ printf "%q" "$FLAG_MESSAGE"
"I\ HAVE\ CLEARED\ LEVEL\ 5.\ I\ Deserve\ appreciation."
이번 편은 여기까지입니다. 저희는 독자 여러분께 항상 유용한 정보를 꾸준히 전달하고자 노력하고 있습니다. 이번 글에서 다룬 내용은 방대하기 때문에 나머지 주제들은 다음 편에서 예제와 함께 계속 다룰 예정이며, '변수의 속성(Attribute)', '변수 내보내기(Export)' 등의 내용이 포함될 예정입니다.
그때까지 Tecmint.com과 계속 소통해 주시기 바랍니다. 아래 댓글란에 소중한 피드백을 남겨주시는 것도 잊지 말아 주세요!