Skip to content
Advertisement

Bash: if statement always succeeding

I have the following if statement to check if a service, newrelic-daemon in this case, is running…

if [ $(ps -ef | grep -v grep | grep newrelic-daemon | wc -l) > 0 ]; then
    echo "New Relic is already running."

The problem is it’s always returning as true, i.e. “New Relic is already running”. Even though when I run the if condition separately…

ps -ef | grep -v grep | grep newrelic-daemon | wc -l

… it returns 0. I expect it to do nothing here as the value returned is =0 but my IF condition says >0.

Am I overlooking something here?

Advertisement

Answer

You are trying to do a numeric comparison in [] with >. That doesn’t work; to compare values as numbers, use -gt instead:

if [ "$(ps -ef | grep -v grep | grep -c newrelic-daemon)" -gt 0 ]; then

The quotation marks around the command expansion prevent a syntax error if something goes horribly wrong (e.g. $PATH set wrong and the shell can’t find grep). Since you tagged this bash specifically, you could also just use [[]] instead of [] and do without the quotes.

As another Bash-specific option, you could use (()) instead of either form of square brackets. This version is more likely to generate a syntax error if anything goes wrong (as the arithmetic expression syntax really wants all arguments to be numbers), but it lets you use the more natural comparison operators:

if (( "$(ps -ef | grep -v grep | grep -c newrelic-daemon)" > 0 )); then

In both cases I used grep -c instead of grep | wc -l; that way I avoided an extra process and a bunch of interprocess I/O just so wc can count lines that grep is already enumerating.

But since you’re just checking to see if there are any matches at all, you don’t need to do either of those; the last grep will exit with a true status if it finds anything and false if it doesn’t, so you can just do this:

if ps -ef | grep -v grep | grep -q newrelic-daemon; then

(The -q keeps grep from actually printing out the matching lines.)

Also, if the process name you’re looking for is a literal string instead of a variable, my favorite trick for this task is to modify that string like this, instead of piping through an extra grep -v grep:

if ps -ef | grep -q 'newrelic[-]daemon'; then

You can pick any character to put the square brackets around; the point is to create a regular expression pattern that matches the target process name but doesn’t match the pattern itself, so the grep process doesn’t find its own ps line.

Finally, since you tagged this linux, note that most Linux distros ship with a combination ps + grep command called pgrep, which does this for you without your having to build a pipeline:

if pgrep newrelic-daemon >/dev/null; then 

(The MacOS/BSD version of pgrep accepts a -q option like grep, which would let you do without the >/dev/null redirect, but the versions I’ve found on Linux systems don’t seem to have that option.)

There’s also pidof; I haven’t yet encountered a system that had pidof without pgrep, but should you come across one, you can use it the same way:

if pidof newrelic-daemon >/dev/null; then 
User contributions licensed under: CC BY-SA
4 People found this is helpful
Advertisement