0

k.sh:

if ! [ -x "$(command -v nvm)" ]; then
    echo 'Error: nvm is not installed' >&2
else
    echo 'nvm installed'
fi

Terminal:

km@Karl ~/dev/cac (master) $ nvm  --version
0.33.2
km@Karl ~/dev/cac (master) $ . k.sh
Error: nvm is not installed

I'd like to have bash check if the command exists! NVM is sourced in .bash_profile and .bashrc.

basickarl
  • 31,830
  • 51
  • 195
  • 300

2 Answers2

2

[ -x ] tests if a file exists and is executable. It will fail if you pass the name of a shell function or alias. There's no real need for the extra check. Simply checking if command succeeded is enough.

if ! command -v nvm &> /dev/null
John Kugelman
  • 330,190
  • 66
  • 504
  • 555
1

hash is for me the most portable:

if hash nvm 2>/dev/null; then echo exists; else echo does not exist; fi

Why it does not work? Let's see what you do:

command -v nvm # prints nothing and exits with 1
$(command -v nvm) # prints nothing and exits with 1
[ -x "$(command -v nvm)" ] exit status of command is ignored. Only the string returned by the command matters. So it is executed like this:
[ -x "" ] test command exits with status 1, as the file "" is not an executable (such file does not exists).
! [ -x "" ] then you negate the return status, so it returns 0, i.e. true

If you which to use command -v to check if a file exists, check for it's return status, not the string:

if command -v nvm 2>/dev/null; then echo exists; else echo does not exist; fi

But hash is a bit more portable, better stick to hash.

Jason Aller
  • 3,475
  • 28
  • 40
  • 37
KamilCuk
  • 96,430
  • 6
  • 33
  • 74
  • How is `hash` more portable than `command`? Both are defined by POSIX. – chepner Aug 10 '18 at 12:19
  • After reading [this](https://stackoverflow.com/questions/592620/how-to-check-if-a-program-exists-from-a-bash-script) i am now convinced in favor of command. The second answer even has `[ -x "$(command -v foo)" ]`, so i'm puzzled right now. – KamilCuk Aug 10 '18 at 12:24
  • It's checking something different. With that command, not only does `foo` have to be a command, but it has to be an executable file, not an alias or function or shell built-in. – chepner Aug 10 '18 at 12:35