Computer >> 컴퓨터 >  >> 프로그래밍 >> Bash 프로그래밍

Bash 환경 변수 완벽 가이드 – 개념부터 설정과 활용까지

컴퓨팅에서 변수(variable)는 변할 수 있는 값을 대신하는 단어입니다. 사실 우리는 일상 대화 속에서도 이미 변수를 사용하고 있습니다. "내 차"라고 말할 때, "내 차"는 일종의 변수로서 현재 내가 소유한 자동차를 가리킵니다. 시간이 지나면서 차종과 모델은 분명 바뀌겠지만, "내 차"라는 변수를 만들어 두면 매번 어떤 차를 소유하고 있는지 길게 설명하지 않아도 됩니다.

컴퓨터에서도 변수는 비슷한 방식으로 사용됩니다.

예를 들어, 컴퓨터에 사용자 계정을 가진 사람은 누구나 자신의 개인 데이터가 저장되는 홈 디렉터리를 갖습니다. 하지만 사용자마다 홈 디렉터리 경로는 서로 다릅니다(Seth는 /home/seth, Tux는 /home/tux 등). 따라서 홈 디렉터리를 일반적으로 지칭하려면 $HOME이라는 변수를 사용하여, 로그인 이름과 무관하게 현재 사용자의 홈 디렉터리를 나타낼 수 있습니다.

환경 변수(environment variable)는 $HOME처럼 로그인 세션에 대한 정보를 담고 있는 특별한 변수입니다. 이 변수들은 시스템 셸이 명령어를 실행할 때 사용하기 위해 저장되며, Linux, Mac, Windows 어디에서든 존재합니다. 많은 환경 변수는 설치 과정이나 사용자 계정 생성 시점에 기본값으로 설정됩니다.

환경 변수는 모든 현대 운영체제에 적용되지만, 이 글에서는 Linux, BSD, Mac, Cygwin의 Bash 셸에서의 환경 변수를 다룹니다.

환경 변수 이해하기

기술적으로 환경 변수는 일반 변수와 전혀 다르지 않습니다. 변수와 정확히 같은 문법으로 설정하고, 불러오고, 삭제할 수 있습니다. Bash에서 변수를 사용하는 데 아직 익숙하지 않다면, 계속 읽기 전에 Bash 변수 관련 자료를 먼저 참고하는 것이 좋습니다.

사실 환경 변수를 직접 다루는 일은 드뭅니다. 주로 개별 애플리케이션과 데몬이 필요할 때 참조합니다. 예를 들어, 홈 디렉터리는 로그인할 때 환경 변수로 설정됩니다. Linux에서 HOME 환경 변수의 내용은 다음과 같이 확인할 수 있습니다:

$ echo $HOME
HOME=/home/seth

Mac에서는 다음과 같습니다:

$ echo $HOME
HOME=/Users/bogus

Windows에서는 다음과 같습니다:

C:\Users\bogus

env 명령을 사용하면 시스템에 설정된 모든 환경 변수를 한눈에 볼 수 있습니다. 목록이 꽤 길기 때문에 more로 파이프하면 읽기가 훨씬 편합니다:

$ env | more
TERM=xterm-256color
LESSOPEN=||/usr/bin/lesspipe.sh %s
USER=seth
SUDO_EDITOR=emacs
WWW_HOME=https://mirror.lagoon.nc/pub/slackware/slackware64-current/ChangeLog.txt
VISUAL=emacs
DISPLAY=:0
PS1=$
XDG_DATA_DIRS=/home/seth/.local/share/flatpak/exports/share/:/var/lib/flatpak/exports/share/:/usr/local/share/:/usr/share/
PATH=/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/snap/bin:/home/seth/bin:/home/seth/.local/bin:/snap/bin
GDMSESSION=gnome
MAIL=/var/spool/mail/seth
[...]

환경 변수는 기본 설정을 재정의하거나, 시스템이 스스로 만들 이유가 없는 새 설정을 관리해야 할 때 특히 유용합니다. 예를 들어 명령어를 입력했을 때 컴퓨터가 해당 명령에 대응하는 애플리케이션을 찾을 수 있는 유일한 이유는, PATH 환경 변수가 어디를 찾아야 하는지 알려주기 때문입니다. 이 변수는 ls나 cp 같은 명령어, Firefox나 Lutris 같은 그래픽 애플리케이션 등 운영체제가 검색할 유효한 디렉터리 목록을 담고 있습니다.

환경 변수마다 이를 사용하는 시스템이 다릅니다. 예를 들어 PATH 변수는 터미널 에뮬레이터에는 필수적이지만, Java처럼 중요한 라이브러리 위치를 가리키는 자체 경로 체계를 갖춘 소프트웨어에는 상대적으로 덜 중요합니다. 반면 USER 변수는 여러 시스템에서 서비스 요청자를 식별하는 수단으로 널리 사용됩니다. 멀티유저 시스템에서 로컬 메일함을 확인해야 한다면, mail 명령은 MAILUSER 변수를 근거로 어떤 메일 스풀을 가져올지 판단합니다.

환경 변수 설정하기

보통 설치 프로그램(Fedora의 dnf, Ubuntu의 apt, Mac의 brew 또는 사용자 지정 설치 프로그램)가 새 애플리케이션을 위해 환경 변수를 알아서 업데이트해 줍니다. 하지만 배포판의 기본 도구 세트 밖에서 무언가를 설치할 때는 직접 환경 변수를 관리해야 할 수 있습니다. 아니면 단순히 취향에 맞게 환경 변수를 추가할 수도 있습니다. 예를 들어 홈 디렉터리의 bin 폴더에 애플리케이션을 보관하기로 했다면, 명령어 입력 시 운영체제가 그곳에서 실행할 프로그램을 찾도록 PATH에 해당 디렉터리를 추가해야 합니다.

임시 환경 변수

일회용 변수를 만드는 방식으로 경로에 위치를 추가할 수 있습니다. 동작은 하지만, 시스템 경로를 수정한 셸이 열려 있는 동안에만 유효합니다. 예를 들어 Bash 셸을 열고 시스템 경로를 수정해 봅시다:

$ export PATH=$PATH:/home/seth/bin

결과를 확인합니다:

$ echo $PATH
PATH=/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/snap/bin:/home/seth/bin:/home/seth/.local/bin:/snap/bin:/home/seth/bin

세션을 종료합니다:

$ exit

새 셸을 열고 PATH 변수를 다시 살펴봅니다:

$ echo $PATH
PATH=/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/snap/bin:/home/seth/bin:/home/seth/.local/bin:/snap/bin

변수가 기본 상태로 되돌아갔습니다. 새 셸이 시작될 때마다 PATH가 설정되지 않기 때문입니다. 이를 해결하려면 셸이 실행될 때마다 변수가 로드되도록 구성해야 합니다.

영구 환경 변수

셸 구성 파일에서 자신만의 영구적인 환경 변수를 설정할 수 있으며, 가장 널리 쓰이는 파일은 ~/.bashrc입니다. 여러 사용자를 관리하는 시스템 관리자라면 /etc/profile.d 디렉터리에 스크립트를 두어 환경 변수를 설정할 수도 있습니다.

구성 파일로 변수를 설정하는 문법은 셸에서 직접 설정할 때와 동일합니다:

export PATH=$PATH:/snap/bin:/home/seth/bin

현재 셸을 닫거나, 업데이트된 설정을 강제로 로드합니다:

$ . ~/.bashrc

마지막으로 시스템 경로를 다시 확인합니다:

$ echo $PATH
PATH=/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/snap/bin:/home/seth/bin:/home/seth/.local/bin:/snap/bin:/home/seth/bin

이제 추가한 사용자 지정 디렉터리가 포함되어 올바르게 설정된 것을 확인할 수 있습니다.

다른 환경 변수 찾아보기

환경 변수는 마음대로 만들고 조작할 수 있으며, 실제로 일부 애플리케이션은 그렇게 합니다. 이 말은 곧, 많은 환경 변수가 대부분의 애플리케이션에서 사용되지 않으며, 임의로 추가한 변수 중 일부는 아무 곳에서도 쓰이지 않을 수 있다는 뜻입니다. 그렇다면 어떤 환경 변수가 실제로 의미 있는지 어떻게 알 수 있을까요?

답은 애플리케이션의 문서에 있습니다. 예를 들어 일반적인 Bash 환경에서 어떤 옵션을 사용할 수 있는지 알고 싶다면 Bash 공식 문서를 읽으면 됩니다. Bash man 페이지에도 많은 중요한 변수가 언급되어 있지만, GNU info 페이지의 Bash 문서에는 Bourne Shell과 Bash 환경 변수의 유용한 목록과 각 변수의 용도가 철저하게 정리되어 있습니다.

예를 들어 info 페이지 목록에는 다음과 같은 항목이 있습니다:

'HISTCONTROL'
A colon-separated list of values controlling how commands are saved
on the history list. If the list of values includes 'ignorespace',
lines which begin with a space character are not saved in the
history list. A value of 'ignoredups' causes lines which match the
previous history entry to not be saved. A value of 'ignoreboth' is
shorthand for 'ignorespace' and 'ignoredups'.
[...]

이 출력은 HISTCONTROL 환경 변수가 Bash 히스토리가 기록·표시되는 방식을 제어하며, 어떤 값을 사용해 이 동작을 사용자 지정할 수 있는지 알려줍니다. 이 예에서 ignoredups 값은 history 명령의 출력에서 중복된 줄을 무시하도록 합니다.

이것은 아주 쉽게 테스트해 볼 수 있습니다. 먼저 같은 명령을 연속으로 두 번 실행합니다:

$ echo "hello world"
hello world
$ echo "hello world"
hello world

히스토리의 최근 항목을 확인합니다:

$ history | tail -5
996 man bash
997 info bash
998 echo "hello world"
999 echo "hello world"
1000 history

중복 항목이 실제로 그대로 나열되어 있는 것을 볼 수 있습니다.

이제 info 페이지에서 읽은 내용을 바탕으로 .bashrc 파일에 새 환경 변수를 설정합니다:

export HISTCONTROL=$HISTCONTROL:ignorespace:ignoredups

저장한 후 새 설정을 로드합니다:

$ source ~/.bashrc

두 명령을 연속으로 두 번씩 실행합니다:

$ echo "hello once"
hello once
$ echo "hello once"
hello once

히스토리의 최근 항목을 다시 확인합니다:

$ history | tail -5
1000 history
1001 emacs ~/.bashrc
1002 source ~/.bashrc
1003 echo "hello once"
1004 history

info 페이지에서 설명한 대로, 새 환경 변수 덕분에 중복 항목이 하나로 병합되었습니다.

결국 관련 환경 변수를 찾는 일은 대개 영향을 주고 싶은 애플리케이션의 문서를 읽는 문제입니다. 대부분의 환경 변수는 특정 애플리케이션이 원활하게 실행되는 데 필요한 것들이며, 일반적인 항목은 셸의 문서를 찾아보는 것이 가장 자연스럽습니다. 새 환경 변수가 필요한 스크립트나 애플리케이션을 직접 작성한다면, 반드시 자신의 문서에 해당 변수들을 정의해 두는 습관을 들이세요.