1

I am testing whether command exist like this:

if hash pm2 2>/dev/null; then
    echo "already exist"
else
    npm install --global pm2
fi

but in fact I just want to do this

if not exist
   install it
fi

I tried this

if [ ! hash pm2 2>/dev/null ]; then
    npm install --global pm2
fi

it is not ok

fedorqui
  • 275,237
  • 103
  • 548
  • 598
roger
  • 9,063
  • 20
  • 72
  • 119

1 Answers1

2

Just negate the condition in your if:

if ! hash pm2 2>/dev/null; then
#  ^
    npm install --global pm2
fi

If you want to use the test command [ you have to enclose the command within a $() to get it evaluated:

if [ ! $(hash pm2 2>/dev/null) ]; then

Example

Let's create an empty file:

$ touch a

And check if it does not contain some text, eg, 5:

$ if ! grep -sq 5 a; then echo "no 5 here"; fi
no 5 here
$ if [ ! $(grep -sq 5 a) ]; then echo "no 5 here"; fi
no 5 here
fedorqui
  • 275,237
  • 103
  • 548
  • 598
  • 1
    Good answer. One thing, probably you want `grep -sq` instead of just `grep -q` – hek2mgl Apr 26 '16 at 08:24
  • @hek2mgl interesting! I always use `-q` for this, I wasn't aware of this one. Is there a significant difference among them? – fedorqui Apr 26 '16 at 08:25
  • 1
    `-s` would additionally suppress error messages about nonexistent or unreadable files. – hek2mgl Apr 26 '16 at 08:26
  • 1
    `if [ ! $( … ) ]` seems brittle and unnecessary. It has not the same meaning as negating the exit status. Rather, if I see correctly, it tests whether the standard output of the command was empty, which might be what you want but it is not the same. – 5gon12eder Apr 26 '16 at 08:39
  • @5gon12eder I believe this depends on the command. For example, `[ $(ls asdfasdfasd) ] && echo "yes" || echo "no"` returns `no` because the exit status of `ls` is not 0 if there were problems. Same happens with `[ $(echo $adfasdf) ] && echo "yes" || echo "no"`. It prints "no" because the exit status of `echo` must be !0 if it cannot find a variable. – fedorqui Apr 26 '16 at 11:34
  • 1
    Yes, it depends on the command whether “no standard output” and “unsuccessful termination” are equivalent. That's what I meant with “brittle”. I don't believe your reasoning about the examples is correct, though. Note that `[ ]` returns failure while `[ xyz ]` (any non-empty string will do) will return success. Assuming `asdfasf` neither refers to a set shell variable or an existing file-system object, `ls asdfasdf` prints an error to standard *error* output and produces no output, so `[ $(ls asdfasdf) ]` reports failure. `echo $asdfasdf` *exits successfully* but only outputs a new-line. – 5gon12eder Apr 27 '16 at 16:16
  • 1
    Therefore, `[ $(echo $asdfasdf) ]` reports failure, too. However, consider how both of the conditions `[ $(false) ]` and `[ $(true) ]` report failure and given `f(){ echo "x"; return $1; }`, both, `[ $(f 0) ]` (where `f` succeeds) and `[ $(f 1) ]` (where `f` fails) report success. – 5gon12eder Apr 27 '16 at 16:19
  • 1
    @5gon12eder thanks for the insight. Your comments left me thinking and prompted me to ask a question about it: [When is “\[ $(command) \]” equivalent to “if command; then…”?](http://stackoverflow.com/q/37049903/1983854). So basically my assumption was wrong. – fedorqui May 05 '16 at 12:31