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
  • 37,187
  • 64
  • 214
  • 335

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
  • 349,597
  • 67
  • 533
  • 578
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,541
  • 28
  • 38
  • 38
KamilCuk
  • 120,984
  • 8
  • 59
  • 111
  • 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