nvm icon indicating copy to clipboard operation
nvm copied to clipboard

Please fix the setup script for macOS

Open anton-bedrock opened this issue 1 year ago • 14 comments

On macOS there setup script mentioned bash completions, but it should be zsh completions instead. An easy fix, but it will save hours for many macOS users. Please fix it.

After running the following command to install NVM.

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.2/install.sh | bash

my .zshrc file had the following added.

export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"  # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"  # This loads nvm bash_completion

After restarting the terminal, it appeared.

zsh compinit: insecure directories, run compaudit for list.
Ignore insecure directories and continue [y] or abort compinit [n]?

After changing bash_completion to zsh_completion, the error disappeared.

Originally posted by @amlzq in #2361

anton-bedrock avatar Apr 06 '25 10:04 anton-bedrock

Not all Mac OS users use zsh, so it definitely shouldn’t do it by platform.

ljharb avatar Apr 07 '25 04:04 ljharb

@ljharb said:

Not all Mac OS users use zsh, so it definitely shouldn’t do it by platform.

I think last 2-3 years macOS ships with zsh. So you always can check if zsh is available and use one output, with a fallback to bash. Seems an easy check

anton-bedrock avatar Apr 07 '25 07:04 anton-bedrock

Yes, that's true, but if you've continuously migrated your Mac environment from prior to that, then you'll stay on bash, as I have.

zsh is always available now, that can't be used to make a choice.

I have a .bashrc, .bash_profile, and .zshrc present, but bash is my default. What logic would you suggest that can select "bash" for me but "zsh" for you?

ljharb avatar Apr 07 '25 18:04 ljharb

https://support.apple.com/en-us/102360

zsh (Z shell) is the default shell for all newly created user accounts, starting with macOS Catalina.

https://en.wikipedia.org/wiki/MacOS_Catalina

macOS Catalina [was] released to the public on October 7, 2019

https://endoflife.date/macos

macOS 10.15 (Catalina) support ended 12 Sep 2022

sdavids avatar Apr 11 '25 10:04 sdavids

if you've continuously migrated your Mac environment from prior to that

Not everybody is as old as we are 😉

sdavids avatar Apr 11 '25 10:04 sdavids

I have a .bashrc, .bash_profile, and .zshrc present, but bash is my default. What logic would you suggest that can select "bash" for me but "zsh" for you?

You always can see in which shell you run the installation script (bash, zsh, etc), right? Depending on it you can write to terminal the correct instructions. I think you can see how other projects achieve this. Or if no luck with detection, write few possible lines - each for each supported shell.

anton-bedrock avatar Apr 11 '25 10:04 anton-bedrock

https://stackoverflow.com/questions/3327013/how-to-determine-the-current-interactive-shell-that-im-in-command-line

Unfortunately, the output of ps -p $$ is not standardized and some terminals report it incorrectly.

$BASH or $ZSH_NAME usually indicate the shell used but it is not reliable either.

But I think a 90% solution is better then doing nothing:

If $ZSH_NAME or ps -p $$ contains the string zsh do the zsh installation otherwise do the bash installation.

sdavids avatar Apr 11 '25 11:04 sdavids

I'd be happy to review a PR that did that - noting that the install script must always run in bash.

ljharb avatar Apr 11 '25 19:04 ljharb

I experimented a little:

$ sw_vers
ProductName:	macOS
ProductVersion:	12.7.6
BuildVersion:	21H1320
$ ps -p $$
  PID TTY           TIME CMD
77576 ttys002    0:00.20 -zsh
$ echo $SHELL
/bin/zsh
$ echo $ZSH_NAME
zsh

$ mkdir /tmp/test && cd "$_"
$ printf '#!/usr/bin/env bash\necho $(ps -p $$)\necho $SHELL\necho $BASH\necho $ZSH_NAME\n' >install.sh
$ chmod u+x install.sh

$ curl -so- file:///tmp/test/install.sh | zsh
PID TTY TIME CMD 78615 ttys001 0:00.01 zsh
/bin/zsh

zsh
$ curl -so- file:///tmp/test/install.sh | bash
PID TTY TIME CMD 78651 ttys001 0:00.01 bash
/bin/zsh
/usr/local/bin/bash

$ zsh -c 'curl -so- curl -so- file:///tmp/test/install.sh | zsh'
PID TTY TIME CMD 78691 ttys001 0:00.01 zsh
/bin/zsh

zsh
$ zsh -c 'curl -so- curl -so- file:///tmp/test/install.sh | bash'
PID TTY TIME CMD 78702 ttys001 0:00.01 bash
/bin/zsh
/usr/local/bin/bash

$  bash -c 'curl -so- curl -so- file:///tmp/test/install.sh | zsh'
PID TTY TIME CMD 78767 ttys001 0:00.01 zsh
/bin/zsh

zsh
$ bash -c 'curl -so- curl -so- file:///tmp/test/install.sh | bash'
PID TTY TIME CMD 78755 ttys001 0:00.01 bash
/bin/zsh
/usr/local/bin/bash

$ docker run -it --rm -v /tmp/test:/tmp/test ubuntu:noble-20250404 bash
# apt-get -y update && apt-get -y install curl
# curl -so- file:///tmp/test/install.sh | bash
PID TTY TIME CMD 2927 pts/0 00:00:00 bash
/bin/bash
/usr/bin/bash

# exit
$ docker run -it --rm -v /tmp/test:/tmp/test ubuntu:noble-20250404 bash
# apt-get -y update && apt-get -y install curl zsh
# zsh
# ps -p $$
  PID TTY          TIME CMD
 3025 pts/0    00:00:00 zsh
# curl -so- file:///tmp/test/install.sh | bash
PID TTY TIME CMD 3047 pts/0 00:00:00 bash
/bin/bash
/usr/bin/bash

# curl -so- file:///tmp/test/install.sh | zsh
PID TTY TIME CMD 3050 pts/0 00:00:00 zsh


zsh
# exit
# zsh -c 'curl -so- curl -so- file:///tmp/test/install.sh | bash'
PID TTY TIME CMD 3056 pts/0 00:00:00 bash
/bin/bash
/usr/bin/bash

# zsh -c 'curl -so- curl -so- file:///tmp/test/install.sh | zsh'
PID TTY TIME CMD 3061 pts/0 00:00:00 zsh


zsh

As expected, a mess 🫣

sdavids avatar Apr 13 '25 10:04 sdavids

There are three options:

  1. do nothing
  2. if one of ps -p $$, $SHELL, or $ZSH_NAME contains zsh then install zsh completions instead of bash completions
  3. same as 2. but also mention curl .../install.sh | zsh in docs

2. and 3. could either install zsh completions immediately or ask something along the lines "It seems that you are you using zsh; do you want to install zsh completions instead of bash completions?"

sdavids avatar Apr 13 '25 11:04 sdavids

I do not think zsh_completion is a thing, and modifying the name of the script in your .zshrc to it is not a real fix. I ran into this on Apple Silicon with a two-user setup where some Homebrew completions have mixed ownership.

The issue is that NVM's bash_completion script calls compinit during shell initialization, but this happens before the shell has properly set up the completion system, causing zsh to flag the mixed-ownership completion files as insecure and abort initialization.

My workaround is to temporarily disable the security check just during NVM initialization in .zshrc:

ZSH_DISABLE_COMPFIX=true
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"  # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"  # This loads nvm bash_completion
unset ZSH_DISABLE_COMPFIX

This allows the completion system to initialize properly while maintaining security for any future completion loading.

codypotter avatar Aug 12 '25 20:08 codypotter

perhaps that's something we could do inside bash_completion, around the compinit call?

ljharb avatar Aug 13 '25 05:08 ljharb

Sorry gang: I'm new to this stuff, and can't figure out how to stop getting the:

zsh compinit: insecure directories, run compaudit for list. Ignore insecure directories and continue [y] or abort compinit [n]? y%

Every time I open the terminal. I know that the installation script hasn't been fixed yet, but can someone tell me what I (a beginner) have to do to STOP seeing this message every time I open Terminal? (I've tried CodyPotter's .zshrc code in post 12, but it doesn't seem to do anything... but let's not rule out user error... I don't know how to do this!)

mgstreak avatar Oct 06 '25 13:10 mgstreak

Hey guys, I was taking a look at this because I use zsh in both my linux and mac machine and I've never had such issue. After some reviewing I might have found a solution and it is covered in this Stackoverflow post and also in this legendary zsh forum email.

There are some points to cover: First the problem is not related to nvm itself. Second, making the change from "$NVM_DIR/bash_completion" to "$NVM_DIR/zsh_completion" removed the errors because there is no such file called zsh_completion, the problem is not within the name of the file but with the function the file is execution. If you execute tail -18 $NVM_DIR/bash_completion you will see the following output:

# complete is a bash builtin, but recent versions of ZSH come with a function
# called bashcompinit that will create a complete in ZSH. If the user is in
# ZSH, load and run bashcompinit before calling the complete function.
if [[ -n ${ZSH_VERSION-} ]]; then
  # First calling compinit (only if not called yet!)
  # and then bashcompinit as mentioned by zsh man page.
  if ! command -v compinit > /dev/null; then
    autoload -U +X compinit && if [[ ${ZSH_DISABLE_COMPFIX-} = true ]]; then
      compinit -u
    else
      compinit
    fi
  fi
  autoload -U +X bashcompinit && bashcompinit
fi

complete -o default -F __nvm nvm

At the end of the bash_completion file it is being executed the compinit command which is related to error being thrown:

zsh compinit: insecure directories, run compaudit for list.
Ignore insecure directories and continue [y] or abort compinit [n]? y%

What you could do is, run the following commands as mentioned in both stackoverflow post and zsh user email:

sudo chmod -R 755 /usr/local/share/zsh/site-functions
# If the chmod didn't worked try this too:
# The -L param is used to update the symlinks if there is any:
# sudo chown -RL root:staff /usr/local/share/zsh

For more info I really recommend reading the zsh user email and stackoverflow post (and also the commentaries) mentioned early. Hope this helps

mr-utzig avatar Oct 17 '25 14:10 mr-utzig