ee: exit all shells
β’ 336 words β’ 2 min
Problem statement: I present this to you the same way I presented it to Amp Code in the context of my ~/.dotfiles:
new shell alias: ee
quit all shells
example:
$ bash
$ bash
$ zsh
Now we're 3 levels deep.
"ee" should quit them all (effectively closing the underlying terminal emulator tab)Why do I even have this issue in the first place? Utilities like
wt (to manage git
worktrees) and try (to
manage scratch directories) need to change directories. Alas, it’s not possible
to change the current working directly ($PWD) with a script. As such, my
workaround is to open a subshell in the desired directory. As a side effect, I
end up with nested subshells.
Why ee? I close my shell with C-d (Ctrl + D).
In this context I need to press it three times in a row.
dd would have been a natural alias but I’d rather avoid the name clash with
the dd disk cloning util.
ee came next naturally.
This version works in bash but not in zsh:
% which ee
ee () {
pid=$$
pids=$pid
while ppid=$(ps -o ppid= -p "$pid" | tr -d ' ') && [ "$ppid" -gt 1 ] 2> /dev/null
do
case "$(ps -o comm= -p "$ppid" 2>/dev/null)" in
(*sh) pids="$pids $ppid"
pid=$ppid ;;
(*) break ;;
esac
done
kill -HUP $pids
}The issue is
zshdoesn’t word-split unquoted variables likebash/shdoes.$pidsis passed as a single string. Fix witheval:
The version below works in both bash and zsh:
ee () {
pid=$$
pids=$pid
while ppid=$(ps -o ppid= -p "$pid" | tr -d ' ') && [ "$ppid" -gt 1 ] 2> /dev/null
do
case "$(ps -o comm= -p "$ppid" 2>/dev/null)" in
(*sh) pids="$pids $ppid"
pid=$ppid ;;
(*) break ;;
esac
done
eval "kill -HUP $pids"
}The only difference is the last line:
- kill -HUP $pids
+ eval "kill -HUP $pids"
The resulting solution is a shell function, not an alias, but that’s perfectly acceptable.