まあ、タイトルの通りなんだけども、ttys000からttys004みたいな感じでタブを複数同時に開いているものの、それぞれのタブで作業する内容はほぼ固定されていて、macOSを再起動した後にも同じ作業を履歴から実行したい。タブ毎にhistoryを保存し、それを次回起動時に読み出す方法は無いんかなぁ、ということで弄くり回したところ、結構厄介な問題があることが分かった。
履歴の保存のフロー
まず、zshがどのようにhistoryを保存しているかというと、~/.zsh_sessions/に$TERM_SESSION_ID.historynewというファイルを作成し、これは$HISTFILEに設定されている。
% echo $HISTFILE
/Users/rifujita/.zsh_sessions/7BB7882E-5A7F-48FC-B619-DA5894386606.historynew
で、そのプロセス(tty)が終了すると、~/.zsh_sessions/に、$TERM_SESSION_ID.historyと$TERM_SESSION_ID.sessionというファイルに記録する。
% cat .zsh_sessions/7BB7882E-5A7F-48FC-B619-DA5894386606.session
echo Restored session: "$(/bin/date -r 1729569658)"
% cat .zsh_sessions/7BB7882E-5A7F-48FC-B619-DA5894386606.history
exit
cd .zsh_sessions
...
2つのタブを開いて作業すると、たぶん以下のように動作する。
- ttys000が起動、.zsh_historyを読み込む
- ttys001が起動、.zsh_historyを読み込む
- ttys000でコマンド[1]を実行、メモリ上のhistoryに保存される
- ttys001でコマンド[2]を実行、メモリ上のhistoryに保存される
- ttys000を終了、.zsh_history + コマンド[1]がttys000の$TERM_SESSION_ID.historyに保存される。
- ttys001を終了、ttys000の$TERM_SESSION_ID.history + コマンド[2]がttys001の$TERM_SESSION_ID.historyに保存される。ここで、ttys001で実行していないコマンド[1]がhistoryに混入する。
むぅ、なんでマージしちゃうんだ…。unsetopt share_historyしても、この挙動は変わらなかった。
trapしよう
ちょっと考え方を変えて、そもそものzshの履歴保存のフローをイジることを諦め、ttyの終了時に独自の方法で履歴を保存することを考えた。.zprofileに以下を追加する。
MYTTY=`basename $(tty)`
last_session_history=$(ls -t -1 $HOME/.zsh_sessions/${MYTTY}*.history | head -n 1)
cp -f $last_session_history $HOME/.zsh_history
trap 'history | sed "s/^ *[0-9]* *//" > $HOME/.zsh_sessions/$MYTTY-$TERM_SESSION_ID.history;chmod 600 $HOME/.zsh_sessions/$MYTTY-$TERM_SESSION_ID.history' EXIT
1行目で、タブが対応しているttyを取得する。
2行目で、前回の終了時に保存された履歴の最も新しいhistoryファイルを見つける。
3行目で、上で見つけたhistoryファイルを、.zsh_historyとして上書きコピーする。
4行目は、タブの終了時(ttyからの切断時)に、historyコマンドを実行し、tty名-セッションID.historyというファイルに保存する。これは、次回起動時に、そのtty用のhistoryファイルとなる。
スクショが撮れないので、タブではなくマルチウインドウでやってみたのが以下。まず、ttys000で存在しないコマンド”1″を、ttys001で”2″、ttys002で”3″を実行し、ターミナル.appを終了する。
ターミナル.appを起動して、ウインドウを複数開いて、historyコマンドを実行する。
tty毎に履歴を保存できていることが分かる。
追記:I wanted to separate the command histories for each tabs / windows with zsh on macOS.
追記:chmod 600を追加。