A month ago, Thorsten Ball wrote How fast is your shell?, encouraging users to profile their shells to make sure they start up quickly. His results are about 70ms - better than mine, but I still think mine are OK.
> /usr/bin/time zsh -i -c exit
0.18 real 0.05 user 0.04 sys
A couple of days later, Laurence Tratt wrote Faster Shell Startup With Shell Switching, which suggests using different shells for scripts and interactive use. (A real callback to arguments1 about the C shell2 on Usenet!)
This post is about my suggestion for improving shell startup time: precomputation.
I have a script called
dhd-shdetect
that detects a bunch of stuff I want to account for in my shell that rarely changes,
caching it in the file $HOME/.shdetect_dhd.sh
.
Anything that it can precompute is code that doesn’t have to run at every shell startup.
Then, as much as possible,
.zshrc
and .profile
files use the precomputed values rather than running code themselves.
I’m not fanatic about this;
if the best thing to do is run code at shell startup, then I do.
A few examples:
-
I have a script called
pathsetup
which takes a list of paths that may exist, and returns all those in the list that actually do exist. It takes a while to check all these paths, sodhd-shdetect
caches the result.# Stuff that we want to use, only if it exists on the filesystem POSSIBLE_PATHS=" ${HOME}/opt/bin ${HOME}/opt/sbin ${HOME}/.cabal/bin ${HOME}/.cabal/sbin ... dozens more entries " # Stuff we want to ignore even if it does exist IGNORE_PATHS=" ${HOME}/.nvm/* " export PATH=$("$DHD/opt/bin/pathsetup" "$POSSIBLE_PATHS" "$IGNORE_PATHS")
This is saved directly to the
$HOME/.shdetect_dhd.sh
file, which is dot-sourced in the.profile
script. -
Detecting the
ls(1)
implementation indhd-shdetect
requires actually running the binary:DHD_LS_TYPE= if ls --version 2>/dev/null | grep -q GNU; then DHD_LS_TYPE=gnu elif ls -h -G >/dev/null 2>&1; then DHD_LS_TYPE=bsd fi
This means that in
.zshrc
, we only have to read the cached value:case "$DHD_LS_TYPE" in gnu) alias ls="ls -FhN --color=always";; bsd) alias ls="ls -FhG";; *) alias ls="ls -F";; esac
-
dhd-shdetect
looks for specific commands that the profile scripts use if they are available. It saves them to a variable called$DHD_CMDAVAIL
, and provides a function for fast lookups into that variable, avoiding the need to scan$PATH
during shell startup.In
dhd-shdetect
:# Available commands # Can test for them with # test "${DHD_CMDAVAIL#*cmd_name}" != "$DHD_CMDAVAIL" DHD_CMDAVAIL= cmdavail fortune && DHD_CMDAVAIL="$DHD_CMDAVAIL fortune" cmdavail kubectl && DHD_CMDAVAIL="$DHD_CMDAVAIL kubectl" # ... several more
The result saved to
$HOME/.shdetect_dhd.sh
:export DHD_CMDAVAIL="$DHD_CMDAVAIL" # ... # Very fast way to test precomputed command availability dhd_cmdavail() { test "\${DHD_CMDAVAIL#*\$1}" != "\$DHD_CMDAVAIL" return \$? }
Called in
.zshrc
:dhd_cmdavail kubectl && source <(kubectl completion zsh)
I can run as many programs as I want to influence my shell configuration,
but I don’t have to pay the time cost every time my shell starts up.
It’s a significant time savings,
as running dhd-shdetect
takes over a second:
> /usr/bin/time dhd-shdetect
Generated data saved to /Users/mrled/.shdetect_dhd.sh
Now log in again, or run the '.z' alias
1.03 real 0.43 user 0.32 sys
That’s time I don’t have to spend waiting for new terminals ✨.
-
This month begins a tutorial on the bad-boy of UNIX, lowest of the low, the shell of last resort. Yes, I am talking about the C shell. FAQ’s flame it. Experts have criticized it. Unfortunately, this puts UNIX novices in an awkward situation. Many people are given the C shell as their default shell. They aren’t familiar with it, but they have to learn enough to customize their environment. They need help, but get criticized every time they ask a question. Imagine the following conversation, initiated by a posting on USENET:
Novice: How do I do XYZ using the C shell?
Expert: You shouldn’t use the C shell. Use the Bourne shell.
Novice: I try to, but I get syntax errors.
Expert: That’s because you are using the C shell. Use the Bourne shell.
Novice: I’ve now using the Bourne shell. How to I create aliases and do command-line editing in the Bourne shell?
Expert: You can’t. use bash, ksh or tcsh.
Novice: I don’t have these shells on all of the systems I use. What can I use?
Expert: In that case, use the C shell.
Novice: But you told me I shouldn’t use the C shell!?!
Expert: Well, if you have to, you can use the C shell. It’s fine for interactive sessions. But you shouldn’t use it for scripts.
Novice: It’s really confusing trying to learn two shells at once. I don’t know either shell very well, and I’m trying to learn JUST enough to customize my environment. I’d rather just learn one shell at a time.
Expert: Well, it’s your funeral.
Novice: How do I do XYZ using the C shell?
Another Expert: You shouldn’t be using the C shell. Use the Bourne shell.
Novice: @#%&!
-
Csh Programming Considered Harmful:
↩︎*** CSH PROGRAMMING CONSIDERED HARMFUL *** Resolved: The csh is a tool utterly inadequate for programming, and its use for such purposes should be strictly banned!