FreeBSD sh에서 현재 디렉터리를 터미널 제목으로 표시하기

터미널을 여러 개 열어 놓고 작업하다 보면 각 터미널이 어느 디렉터리에 있는지 제목 표시줄만 보고 구분하고 싶을 때가 있습니다.

예를 들어 현재 디렉터리가 다음과 같다면,

/home/hodong/projects/nimfsoft.com

터미널 제목에는 다음처럼 표시되도록 만들 수 있습니다.

~/projects/nimfsoft.com

현재 디렉터리가 홈 디렉터리 밖에 있다면 축약하지 않고 전체 경로를 표시합니다.

/usr/local/src

이 글에서는 FreeBSD의 /bin/sh~/.shrc를 기준으로 설정합니다.

터미널 제목 변경 원리

xterm 호환 터미널 에뮬레이터는 OSC(Operating System Command) 이스케이프 시퀀스를 이용하여 터미널 제목을 변경할 수 있습니다.

printf '\033]0;%s\007' '새 터미널 제목'

각 부분의 의미는 다음과 같습니다.

\033    ESC 문자
]0;     아이콘 이름과 창 제목 설정
%s      표시할 문자열
\007    BEL 문자로 OSC 시퀀스 종료

따라서 현재 디렉터리를 그대로 제목으로 지정하려면 다음처럼 작성할 수 있습니다.

printf '\033]0;%s\007' "$PWD"

OSC 제목 변경 기능의 지원 여부는 터미널 에뮬레이터와 설정에 따라 다를 수 있습니다.

홈 디렉터리를 ~로 축약하기

$PWD$HOME과 같거나 그 하위 디렉터리라면 홈 디렉터리 부분을 ~로 표시합니다.

set_terminal_title() {
    if [ -n "${HOME-}" ]; then
        case "$PWD" in
            "$HOME")
                _terminal_title_path='~'
                ;;
            "$HOME"/*)
                _terminal_title_path="~${PWD#"$HOME"}"
                ;;
            *)
                _terminal_title_path=$PWD
                ;;
        esac
    else
        _terminal_title_path=$PWD
    fi

    printf '\033]0;%s\007' "$_terminal_title_path"
    unset _terminal_title_path
}

${HOME-}HOME 변수가 설정되지 않은 경우에도 오류 없이 빈 문자열로 처리되도록 합니다.

홈 디렉터리가 정상적으로 설정된 경우에는 case 문으로 현재 경로를 분류합니다.

case "$PWD" in
    "$HOME")
        _terminal_title_path='~'
        ;;
    "$HOME"/*)
        _terminal_title_path="~${PWD#"$HOME"}"
        ;;
    *)
        _terminal_title_path=$PWD
        ;;
esac

현재 디렉터리가 홈 디렉터리와 정확히 같으면 제목은 ~가 됩니다.

/home/hodong -> ~

현재 디렉터리가 홈 디렉터리의 하위 디렉터리이면 $HOME 부분을 제거한 뒤 앞에 ~를 붙입니다.

/home/hodong/projects/nimfsoft.com
-> ~/projects/nimfsoft.com

${PWD#"$HOME"}$PWD의 앞부분에서 $HOME과 일치하는 가장 짧은 문자열을 제거합니다.

예를 들어 다음 환경에서,

HOME=/home/hodong
PWD=/home/hodong/projects/nimfsoft.com

${PWD#"$HOME"}의 결과는 다음과 같습니다.

/projects/nimfsoft.com

여기에 ~를 붙이면 최종 제목은 다음과 같습니다.

~/projects/nimfsoft.com

"$HOME"/* 패턴을 별도로 사용하므로 /home/hodong2처럼 이름 앞부분만 우연히 같은 다른 디렉터리를 홈 디렉터리 아래로 잘못 판단하지 않습니다.

/home/hodong2/projects
-> /home/hodong2/projects

_terminal_title_path는 셸 함수 안에서 사용하기 위한 임시 변수입니다. FreeBSD sh의 함수 변수는 기본적으로 현재 셸에 남을 수 있으므로, 함수 마지막에서 unset하여 다른 설정과 충돌할 가능성을 줄였습니다.

cd를 실행할 때 제목 갱신하기

셸이 시작될 때 제목을 한 번 설정하는 것만으로는 부족합니다. cd를 실행하여 디렉터리를 이동할 때도 제목을 다시 설정해야 합니다.

다음 함수는 기존 셸 내장 cd를 호출한 뒤, 디렉터리 변경이 성공한 경우에만 터미널 제목을 갱신합니다.

cd() {
    command cd "$@" || return $?
    set_terminal_title
}

함수 안에서 단순히 cd "$@"를 호출하면 같은 이름의 함수가 다시 호출되어 재귀에 빠집니다.

cd "$@"

command cd "$@"를 사용하면 같은 이름의 함수 대신 셸 내장 cd를 실행합니다.

command cd "$@"

"$@"를 사용하므로 사용자가 cd에 전달한 인자를 그대로 유지합니다.

cd
cd -
cd /usr/local/src

디렉터리 변경에 실패하면 실패 상태를 반환하고 제목은 갱신하지 않습니다.

command cd "$@" || return $?

따라서 존재하지 않는 디렉터리로 이동하려고 해도 현재 디렉터리와 터미널 제목은 그대로 유지됩니다.

최종 .shrc 설정

다음 패치를 ~/.shrc에 적용합니다.

--- a/.shrc	2026-07-15 19:28:53.358286000 +0900
+++ b/.shrc	2026-07-15 19:47:56.461994000 +0900
@@ -46,6 +46,37 @@
 bind ^[[5~ ed-move-to-beg
 bind ^[[6~ ed-move-to-end

+# Update terminal title to the current working directory.
+set_terminal_title() {
+    if [ -n "${HOME-}" ]; then
+        case "$PWD" in
+            "$HOME")
+                _terminal_title_path='~'
+                ;;
+            "$HOME"/*)
+                _terminal_title_path="~${PWD#"$HOME"}"
+                ;;
+            *)
+                _terminal_title_path=$PWD
+                ;;
+        esac
+    else
+        _terminal_title_path=$PWD
+    fi
+
+    printf '\033]0;%s\007' "$_terminal_title_path"
+    unset _terminal_title_path
+}
+
+# Change directory and update the terminal title.
+cd() {
+    command cd "$@" || return $?
+    set_terminal_title
+}
+
+# Set the initial terminal title.
+set_terminal_title
+
 # set prompt: ``username@hostname:directory $ ''
 PS1="\u@\h:\w \\$ "

set_terminal_title을 처음 한 번 호출하는 이유는 .shrc를 읽는 시점의 현재 디렉터리를 터미널 제목에 반영하기 위해서입니다.

set_terminal_title

그 뒤에는 cd 함수가 디렉터리 이동에 성공할 때마다 제목을 다시 갱신합니다.

설정을 현재 셸에 적용합니다.

. ~/.shrc

이제 다음처럼 디렉터리를 이동하면,

cd ~/projects/nimfsoft.com

터미널 제목에 다음 경로가 표시됩니다.

~/projects/nimfsoft.com

홈 디렉터리 밖으로 이동하면 전체 경로를 표시합니다.

cd /usr/local/src
/usr/local/src

PS1 안에서 함수를 호출하지 않는 이유

처음에는 다음처럼 PS1 안에서 함수를 호출하는 방법을 생각할 수 있습니다.

PS1='$(set_terminal_title)\u@\h:\w \$ '

그러나 이 구성은 필자가 사용한 FreeBSD sh 환경에서 의도대로 동작하지 않았습니다. 프롬프트가 비정상적으로 표시되었고 터미널 제목도 갱신되지 않았습니다.

따라서 특정한 프롬프트 재평가 동작에 의존하지 않고, 기존 PS1은 그대로 유지했습니다.

PS1="\u@\h:\w \\$ "

대신 디렉터리가 실제로 변경되는 cd 호출을 감싸서, 이동이 성공한 직후 제목을 갱신하도록 구성했습니다.

주의 사항

이 설정은 OSC 제목 변경 시퀀스를 지원하고, 애플리케이션의 제목 변경을 허용하는 터미널 에뮬레이터에서 동작합니다.

터미널 에뮬레이터가 OSC 제목 변경을 지원하지 않거나 보안 설정으로 차단한 경우에는 제목이 바뀌지 않을 수 있습니다.

또한 이 예제는 일반적인 사용자 디렉터리 이름을 가정합니다. 디렉터리 이름에 ESC나 BEL 같은 터미널 제어 문자가 포함된 특수한 환경에서는 경로를 그대로 터미널 제어 시퀀스에 넣지 않도록 별도의 정제가 필요합니다.

이 설정은 사용자가 cd 함수를 통해 디렉터리를 변경할 때 제목을 갱신합니다. 셸 시작 시에는 set_terminal_title을 한 번 직접 호출하여 초기 제목을 설정합니다.

전체 동작 요약

터미널 제목은 다음 규칙으로 표시됩니다.

/home/hodong                       -> ~
/home/hodong/projects              -> ~/projects
/home/hodong/projects/nimfsoft.com -> ~/projects/nimfsoft.com
/home/hodong2/projects             -> /home/hodong2/projects
/usr/local/src                     -> /usr/local/src

작은 설정이지만 여러 프로젝트의 터미널을 동시에 열어 놓고 작업할 때 현재 위치를 빠르게 구분할 수 있어 편리합니다.