If, else based on command piped to grep

7

3

I can't figure out how to make this (what supposed to be simple) script to work. Basically what I want, to run different stuff based on the state of my Parallels vm, something like this:

if [ prlctl list --info ubuntu-vm | grep State == "State: running" ] ; then 
   echo 'machine is running'
else
   echo 'machine is not running'
fi

Of course that doesn't work

iLemming

Posted 2014-05-07T17:24:28.860

Reputation: 507

Answers

14

The problem is that you are putting it all within [, i.e. the test command. Moreover, your usage of grep is broken.

All you need is:

if prlctl list --info ubuntu-vm | grep -q "State: running"; then
   echo 'machine is running'
else
   echo 'machine is not running'
fi

Note the usage of -q as an argument to grep. It doesn't write anything to STDOUT and exits with a status of 0 if the match is found, and non-zero otherwise.

devnull

Posted 2014-05-07T17:24:28.860

Reputation: 2 987

1A oneliner: prlctl list --info ubuntu-vm | grep -q "State: running" && echo "machine is running" || echo "machine is not running" – Noam Manos – 2019-07-31T12:03:45.173

3

An alternative check, less "clean" but closer to what the question tried to achieve.

Remember that [ at its core is just a command. It always accepts a specific number of parameters, and exits with either 0 (success) or 1 (failure) exit status, as all other commands do. For example, when you're comparing two strings, the syntax is[, string 1, ==, string 2, ].

Right now you're using this as the if condition:

[ prlctl list --info ubuntu-vm | grep State == "State: running" ]

But it's ambiguous in several ways. How would [ know that on the left you have a command to run and not a fixed string? How would it know that the == is the string comparison operator, rather than just an argument to grep? How would it know that the | is part of the left-hand value, rather than separating the command into [ prlctl list --info ubuntu-vm and grep State == "State: running" ]?

So the left side needs to be quoted as well. Also, since you want to compare the output of that command, rather than the worlds "prctl list --info..." themselves, you need the $(…) operator:

[ "$(prlctl list --info ubuntu-vm | grep State)" == "State: running" ]

user1686

Posted 2014-05-07T17:24:28.860

Reputation: 283 655

This was a great answer! – Mercutio – 2018-09-06T21:24:38.407

+1 for the detailed explanation. May I ask, Where have you gained you Shell-Scripting skills? I would love to read something about the Shell, that goes into that detail, like that [ is a command, what probably seems very foreign to someone for whom knows only languages like Java or Python. – Senkaku – 2014-05-07T19:12:50.890

1@Creaturo: It's a scripting language by design, intended to link together shell commands, so it makes sense that the if statement would accept an arbitrary command as the condition (if <command>; then <commands...>; fi). The syntax is described in man bash if you're working with the 'bash' shell. – user1686 – 2014-05-07T19:30:55.210