Today I Learned

6 posts about #zsh

Slow Terminal Startup Tip: Lazy Load NVM

For a long time, my ZSH shell windows/tabs have had very slow startup times, sometimes taking 5-10 seconds before .zshrc fully loads and the input cursor appears. This slows down my daily development cycles.

It turns out that loading NVM was the main culprit. Using this Medium post and this gist as motivation, I have added this snippet to my .zshrc file in order to lazy load nvm, npm, node, and npx (copied from the gist, credit goes to that author). I have immediately observed major speed improvements in my shell speed load times.

lazynvm() {
  unset -f nvm node npm npx
  export NVM_DIR=~/.nvm
  [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" # This loads nvm
  if [ -f "$NVM_DIR/bash_completion" ]; then
    [ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion
  fi
}

nvm() {
  lazynvm 
  nvm $@
}

node() {
  lazynvm
  node $@
}

npm() {
  lazynvm
  npm $@
}

npx() {
  lazynvm
  npx $@
}

Lazy-load NVM to speed up zsh initialization

UPDATE Once appending --no-use, ensure to source $NVM_DIR/.nvm.sh when actually needed. For example, yarn install will complain node: No such file or directory

I was curious as to why the zsh initialization was so slow. After some benchmarking .zshrc, I learned that oh-my-zsh and NVM were the main source of slow-down. For oh-my-zsh, I'm trying to see if I can avoid loading plugins that I rarely use to cut some time. However for nvm, simply passing `--no-use the following will make a big difference.

[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" --no-use

Benchmarking with bash's buil-in time command...

Before --no-use:

❯ for i in $(seq 1 5); do /usr/bin/time zsh -i -c exit; done
        1.43 real         0.65 user         0.62 sys
        2.42 real         0.66 user         0.61 sys
        1.42 real         0.65 user         0.61 sys
        1.42 real         0.65 user         0.61 sys
        2.43 real         0.66 user         0.62 sys

After --no-use:

❯ for i in $(seq 1 5); do /usr/bin/time zsh -i -c exit; done
        0.48 real         0.26 user         0.17 sys
        0.46 real         0.25 user         0.16 sys
        0.46 real         0.25 user         0.16 sys
        0.46 real         0.26 user         0.16 sys
        0.49 real         0.27 user         0.17 sys

Sources:

https://github.com/creationix/nvm/issues/539 https://github.com/michaelmoussa/dotfiles/commit/8d67223aad5885ffc17e540b00e00478dd3c44d2 https://blog.jonlu.ca/posts/speeding-up-zsh

Send commands to all panes in iTerm

Problem

I just edited my shell profile (~/.zshrc). Now I need to remember to reload any pane that needs the changes.

Solution

Send commands to all panes:

  1. Cmd + Shift + I
  2. source ~/.zshrc

Magic!

Skip duplicate history entries in zsh

In zsh, pressing UP searches through the history and brings up all matching commands, even if they are duplicates. That means, sometimes you need to press UP many times to actually find a previous match.

However, it is possible to disable this behaviour and skip duplicate entries from the history. To do that, add one line to your ~/.zshrc:
setopt HIST_FIND_NO_DUPS

Mass replace and copy by file extension

Problem

I just cloned a Rails project. There are a bunch of files with the .yml.sample extension under the config directory.

I'd like to copy all those files without the .sample prefix.

Solution

zsh functions to the rescue!

Add this to your .zshrc file:

autoload -U zmv

Then run:

zmv -C 'config/(*.yml).sample' 'config/$1'

By default, zmv will move files. -C puts it in copy mode.

For more info:

man zshcontrib

Oh-My-Zsh Plugins List

I feel like I just discovered the Internet when I look at this page:

https://github.com/robbyrussell/oh-my-zsh/wiki/Plugins