Bash 셸에는 '~'(틸드)로 시작하는 특수 변수들이 있으며, 이를 활용하는 기능을 틸드 확장(Tilde Expansion)이라고 합니다.
틸드는 셸 내부에 있는 다른 변수들의 값을 대신 가리키는 일종의 별칭(synonym)입니다. 즉, 틸드 확장이란 이러한 약어를 그것이 의미하는 실제 디렉터리 경로로 변환하는 과정을 말합니다.
이 글에서는 다양한 예제와 함께 Bash의 틸드 확장 기능을 자세히 살펴보겠습니다.
틸드 확장의 기본 규칙
틸드 확장은 '~' 뒤에 오는 문자(+, -, 또는 정수 N)에 적용되며, 공백이나 슬래시(/)를 만나면 확장이 종료됩니다.
틸드 확장은 주로 다음과 같은 특정 경로명으로 확장됩니다.
- 홈 디렉터리(Home Directory)
- 현재/이전 작업 디렉터리(Current/Previous Working Directory)
- 디렉터리 스택(Directory Stack)에 저장된 디렉터리
1. 홈 디렉터리 확장
틸드 확장을 사용하면 현재 사용자의 홈 디렉터리 또는 지정된 사용자 이름의 홈 디렉터리로 손쉽게 확장할 수 있습니다.
문법 ~ $HOME 변수 또는 현재 사용자의 홈 디렉터리로 확장 ~USER 지정한 사용자 이름(USER)의 홈 디렉터리로 확장
예제 1. 현재 사용자의 홈 디렉터리
단독으로 사용된 틸드(~)는 $HOME 변수가 정의되어 있다면 그 값으로 확장되고, $HOME이 정의되어 있지 않으면 현재 사용자의 홈 디렉터리 값으로 확장됩니다.
아래 예제에서 HOME 변수의 값은 /home/oracle이므로, cd ~ 명령은 현재 디렉터리를 $HOME 값으로 변경합니다.
## 홈 디렉터리가 /home/oracle인 oracle 사용자로 로그인 # su oracle [tmp]$ pwd /tmp [tmp]$ echo $HOME /home/oracle [tmp]$ cd ~ [~]$ pwd /home/oracle
그런데 HOME 변수를 다른 값으로 바꾸면 어떻게 될까요? 아래 예제에서 HOME을 /sbin으로 변경한 후 cd ~를 실행하면, 실제 홈 디렉터리가 아닌 $HOME 값만을 따라갑니다. 반면 unset으로 HOME 변수를 제거하면, /etc/passwd에 설정된 oracle 사용자의 실제 홈 디렉터리로 이동합니다. 즉, 틸드 확장에서는 HOME 변수가 실제 홈 디렉터리보다 우선권을 가집니다.
[~]$ export HOME=/sbin [oracle]$ cd ~ [~]$ pwd /sbin [~]$ unset HOME [sbin]$ cd ~ [oracle]$ pwd /home/oracle
예제 2. 지정한 사용자의 홈 디렉터리
다음 스크립트는 파일 이름에 현재 날짜가 포함된 로그 파일을 백업하고, 시작 시간과 종료 시간을 oracle 사용자 홈 디렉터리의 backup.log 파일에 기록합니다.
#! /bin/bash
echo "Initiating the backup at `date`" >> ~oracle/backup.log
da=`date +%F`
cp $da.log{,.bak}
echo "END BACKUP at `date`" >> ~oracle/backup.log
$ ls -l /home/oracle/
total 8
-rw-r--r-- 1 root root 99 Jun 4 14:23 backup.log
주의할 점은, 지정한 사용자 이름이 존재하지 않으면 확장이 일어나지 않는다는 것입니다. 아래 예제에서 'ora'라는 사용자는 없으므로, ~ora는 /home/ora로 확장되지 않고 그대로 출력됩니다.
$ echo ~ora ~ora
참고로 중괄호({ })를 활용한 브레이스 확장(Brace Expansion)에 대해서도 이전 글에서 다룬 적이 있으니 함께 참고하시기 바랍니다.
2. 현재/이전 작업 디렉터리 확장
'+' 및 '-'와 함께 사용된 틸드는 작업 디렉터리를 나타내는 데 사용됩니다.
- ~+ : 현재 작업 디렉터리를 담고 있는 PWD 변수의 값으로 확장됩니다.
- ~- : 이전 작업 디렉터리를 담고 있는 OLDPWD 변수의 값으로 확장됩니다. OLDPWD가 설정되어 있지 않으면 확장되지 않습니다.
예제 3. 이전/현재 작업 디렉터리 확장
다음 예제는 현재 디렉터리의 파일과 이전 작업 디렉터리의 파일을 비교합니다.
$ cat comp.sh #! /bin/bash set -x cd /var/opt/gg if [ -f gg.c ] then echo "File1 exists" fi cd /var/opt1/gg if [ -f gg.c ] then echo "File2 exists" cmp ~+/gg.c ~-/gg.c fi $ ./comp.sh + cd /var/opt/gg + '[' -f gg.c ']' + echo 'File1 exists' File1 exists + cd /var/opt1/gg + '[' -f gg.c ']' + echo 'File2 exists' File2 exists + cmp /var/opt1/gg/gg.c /var/opt/gg/gg.c cmp: EOF on /var/opt1/gg/gg.c $
위 실행 결과에서 알 수 있듯이:
~+/gg.c는 /var/opt1/gg/gg.c로 확장됩니다.~-/gg.c는 /var/opt/gg/gg.c로 확장됩니다.
이 글은 진행 중인 Bash 튜토리얼 시리즈의 일부입니다.
3. 디렉터리 스택 확장
각 bash 프로세스는 스택(stack) 객체를 내장하고 있으며, 이를 통해 스크립트가 처리 과정에서 방문한 디렉터리들을 추적할 수 있습니다.
이는 방문했던 디렉터리를 참조하거나 되돌아가기 위한 매우 간단한 메커니즘입니다. 틸드 확장 역시 디렉터리 스택에 있는 디렉터리들로 확장하는 기능을 제공합니다.
- ~+N : 디렉터리 스택에서 N번째 디렉터리로 확장됩니다. 옵션 없이 실행한
dirs명령 출력 목록 기준 왼쪽부터 0부터 세어 계산합니다. - ~-N : 디렉터리 스택에서 N번째 디렉터리로 확장됩니다. 단, 오른쪽부터 0부터 세어 계산합니다.
디렉터리 스택을 조작하는 dirs, pushd, popd 명령의 사용법은 이전 글을 참고하시기 바랍니다.
예제 4. ~+로 왼쪽에서 N번째 디렉터리 표시
다음 예제에서 디렉터리 스택에는 4개의 디렉터리가 있습니다. ~+2는 왼쪽에서 0부터 세었을 때 두 번째 위치에 있는 디렉터리 경로를 반환합니다.
$ dirs -v 0 /sbin 1 /var/opt/midas 2 /var/opt/GG/bin 3 /root $ cd ~+2 $ pwd /var/opt/GG/bin
단, 스택의 맨 위(0번 위치)에는 항상 현재 디렉터리가 위치한다는 점에 유의하세요. 따라서 위 명령 실행 후 디렉터리 스택은 다음과 같이 변경됩니다.
$ dirs -v 0 /var/opt/GG/bin 1 /var/opt/midas 2 /var/opt/GG/bin 3 /root
예제 5. ~-로 오른쪽에서 N번째 디렉터리 표시
다음 예제는 앞선 예제와 유사하지만, ~-를 사용하기 때문에 스택의 아래쪽(오른쪽 끝)에서부터 디렉터리를 계산합니다.
$ dirs -v 0 /var/opt/GG/bin 1 /var/opt/midas 2 /var/opt/GG/bin 3 /root $ cd ~-2 $ pwd /var/opt/midas $ dirs -v 0 /var/opt/midas 1 /var/opt/midas 2 /var/opt/GG/bin 3 /root