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