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"

実際に利用できるかどうかは、端末エミュレーターとその設定に依存します。

ホームディレクトリを ~ に短縮する

$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

の場合、結果は次のようになります。

/projects/nimfsoft.com

先頭に ~ を追加すると、最終的なタイトルは次のようになります。

~/projects/nimfsoft.com

になります。

"$HOME"/* を独立したパターンとして使うため、 /home/hodong2/projects を誤って /home/hodong の配下と判断することは ありません。

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

_terminal_title_path は一時的なシェル変数です。シェル関数内の変数は 通常、現在のシェルに残るため、使用後に unset して名前の衝突を避けます。

cd の実行後にタイトルを更新する

シェル起動時に一度だけタイトルを設定しても、ディレクトリを移動した後は 古い表示のままです。

次の関数は元のシェル組み込み cd を呼び出し、移動に成功した場合だけ タイトルを更新します。

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

関数内で直接 cd "$@" を実行すると、同じ関数を再び呼び出して再帰に なります。

cd "$@"

command cd "$@" を使うと、同名の関数を迂回し、シェル組み込みの cd を実行します。

command 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='$(set_terminal_title)\u@\h:\w \$ '

しかし、この記事で使用した FreeBSD sh 環境では意図どおりに動作せず、 プロンプト表示が崩れ、タイトルも更新されませんでした。

そのため、既存のプロンプトは変更しません。

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

プロンプトの再評価動作には依存せず、cd が成功した直後にタイトルを 更新します。

注意事項

この設定を利用するには、端末エミュレーターが OSC タイトルシーケンスを サポートし、アプリケーションによるタイトル変更を許可している必要が あります。

この記事では一般的なディレクトリ名を想定しています。ディレクトリ名に ESC や BEL などの制御文字が含まれる可能性がある場合は、OSC シーケンスへ 埋め込む前にパスを無害化する必要があります。

タイトルは、ここで定義した cd 関数を通じてディレクトリを変更したときに 更新されます。シェル開始時のタイトルは明示的な最初の呼び出しで設定します。

まとめ

最終的な表示規則は次のとおりです。

/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

小さな設定ですが、複数のプロジェクトを同時に扱うときに端末を区別しやすく なります。