⌨️

Ctrl+Q で zsh を終了するキーバインドを作る

に公開

これは モニクル Advent Calendar 2025 の 20 日目の記事です。

zsh 終了のためのキーバインドをカスタマイズしたお話です。前提として Mac を利用しています。

そもそも zsh は Ctrl+D で終了できる

今回のようなキーバインディングをわざわざ設定する必要もなく、zsh は Ctrl+D(以降 ^D と記載します)で終了できます。EOF が送信されるようになっていて、zsh がそれを受け取ることで終了処理が動作するようになっているようです。

他にも色々 Ctrl+D で終了できる

最近は Rails のアプリケーション開発に携わっているので、Rails Console を使う機会が多いですが、こちらも ^D で終了できます(^C では終了しません)。同じように Python や Node も REPL として実行する際には ^D で終了できますし、SQLite や PostgreSQL のクライアントでも同様です。

ツールごとに終了させるコマンドが異なっている(quit, .quit, \q など)ので、私はむしろ ^D を使う機会が多いです。

うっかり連打 Ctrl+D を回避する

これらのツール上でうっかり ^D を連打してしまうと、zsh も巻き添えで終了してしまうということが起きそうですが、ちゃんと対処法があります。IGNOREEOF という設定があり、これを有効にすると読んで字のごとく EOF(^D) を無視できます。

...あれ、そうなると ^D で zsh が終了できなくなり...ません。

実は完全に無視されるわけではなく ^D10 回 押すと zsh は終了します。10 回です。この回数は変更できません。

さすがに 10 回は面倒くさいですね。

Ctrl+D を素早く 2 回

ところで、今まで挙げたツールと違って、Claude Code では ^C^D を素早く 2 回入力しないと終了しません。(もちろん/exitとかquitとかでも終了はできます)

この「^D を素早く 2 回」って良いですよね。ツール自体も誤操作で終了しなさそうだし、他のツールでもこのような対応ができると便利そうです。

結局どうしたら?

いったん整理してみると以下のようになるでしょうか。

  • zsh、REPL などのツールでは ^D で終了できる
  • zsh には IGNOREEOF があり ^D を無視できる
    • 10 回押すと終了する
    • この回数は変更できない
  • Claude Code だと ^D を 2 回で終了できるし、便利そう

Claude Code のように zsh を終了させるには自前でキーバインドを設定するしかなさそうです。

作ってみた

というわけで「^Q を素早く 2 回入力すると終了する」というスクリプトとキーバインドの設定を試してみました。

なんで Ctrl+Q ?

他とかぶってなければ何でも良かったんですが、既存の割り当てで不都合が起こると困ります。確認したところ ^Q は FlowControl(データ転送の制御)用のキーバインドとして割り当てられているのですが、私は利用していませんでした。

あとはまぁ終了っぽいしなと思って ^Q を採用しました。

作ったコード

実際に作成したものは以下の通りです。~/.zshrc に追記して使用します。

# 前回Ctrl+Qを押した時刻を保存するグローバル変数
typeset -g __quit_timestamp=0

# Ctrl+Q を1秒以内に2回押したら終了、1回だけならメッセージ表示する関数
function _quick_quit() {
  # 現在時刻を取得(Unix時間)
  local current_time=$(date +%s)

  # 前回との差分を計算、1秒以内に再度押された場合は終了
  local time_diff=$((current_time - __quit_timestamp))
  if [[ $time_diff -le 1 ]]; then
    exit
  fi

  # 今回の時刻を記録して、メッセージ表示
  # zle -M はコマンドライン下部にメッセージを表示
  __quit_timestamp=$current_time
  zle -M "Press Ctrl+Q again to quit"
}

# ZLEウィジェットとして登録して、キー入力イベントをフックできる
# 普通の関数だとキーバインドに直接紐付けられない
zle -N _quick_quit
bindkey '^Q' _quick_quit

コメントも書いていますが、改めてざっくり説明すると、

  • _quick_quit: Ctrl+Q を 1 秒以内に 2 回押したら終了、1 回だけならメッセージ表示する関数
  • zle ウィジェットを登録して ^Q のキーバインドを設定

となります。

実際使ってみると

1 回 ^Q を押すとこのように表示されます。

Ctrl+Qを押したときのメッセージ表示

素早くもう一度押すと終了します。

使ってみた正直な感想ですが ^Q の位置というか組み合わせが押しづらいです。間違って ^Tab になってしまってタブが切り替わったりすることがあります。まぁ違うキーにすれば良いだけなんですけど、未だ変えていません。

あとは、1 回押したときにメッセージが出ますが、消せません。zle なんか仕組みで消せそうな気もするんですが、とりあえず動いてるしいっかー。

まぁないよりもある方が便利だな...って感じでした。結局 exit している方が多いかも。

Discussion