Sandra Schlichting
Sandra Schlichting

Reputation: 26046

How to make "if not true condition"?

I would like to have the echo command executed when cat /etc/passwd | grep "sysa" is not true.

What am I doing wrong?

if ! [ $(cat /etc/passwd | grep "sysa") ]; then
        echo "ERROR - The user sysa could not be looked up"
        exit 2
fi

Upvotes: 481

Views: 922216

Answers (8)

gildux
gildux

Reputation: 564

I'd expect to see in the answers the direct use of grep with -q option (as we don't care the result but need only the return code.)

if ! grep -qs "sysa" /etc/passwd; then
        echo "ERROR - The user sysa could not be looked up" >&2
        exit 2
fi

or (to use chained execution on fail)

grep -qs "sysa" /etc/passwd || {
        echo "ERROR - The user sysa could not be looked up" >&2
        exit 2
}

Better, because the opposite is wanted, there's option -v for that

if grep -qsv "sysa" /etc/passwd; then
        echo "ERROR - The user sysa could not be looked up" >&2
        exit 2
fi

or (to use chained execution on success)

grep -qsv "sysa" /etc/passwd && {
        echo "ERROR - The user sysa could not be looked up" >&2
        exit 2
}

Notes

  • I like redirecting error messages to stderr, but echo output to stdout, hence >&2
  • Taylor the search pattern, e.g something like '^sysa:' if it's full login.

Upvotes: 0

shellter
shellter

Reputation: 37318

try

if ! grep -q sysa /etc/passwd ; then

grep returns true if it finds the search target, and false if it doesn't.

So NOT false (! false) == true.

if evaluation in shells are designed to be very flexible, and many times doesn't require chains of commands (as you have written).

Also, looking at your code as is, your use of the $( ... ) form of cmd-substitution is to be commended, but think about what is coming out of the process. Try echo $(cat /etc/passwd | grep "sysa") to see what I mean. You can take that further by using the -c (count) option to grep and then do if ! [ $(grep -c "sysa" /etc/passwd) -eq 0 ] ; then which works but is rather old school.

BUT, you could use the newest shell features (arithmetic evaluation) like

if ! (( $(grep -c "sysa" /etc/passwd) == 0 )) ; then ...`

which also gives you the benefit of using the c-lang based comparison operators, ==,<,>,>=,<=,% and maybe a few others.

In this case, per a comment by Orwellophile, the arithmetic evaluation can be pared down even further, like

if ! (( $(grep -c "sysa" /etc/passwd) )) ; then ....

OR

if (( ! $(grep -c "sysa" /etc/passwd) )) ; then ....

Finally, there is an award called the Useless Use of Cat (UUOC). :-) Some people will jump up and down and cry gothca! I'll just say that grep can take a file name on its cmd-line, so why invoke extra processes and pipe constructions when you don't have to? ;-)

I hope this helps.

Upvotes: 664

Tareq
Tareq

Reputation: 509

This one

if [[ !  $(cat /etc/passwd | grep "sysa") ]]; then
  echo " something"
  exit 2
fi

Upvotes: 50

Mario Palumbo
Mario Palumbo

Reputation: 1007

simply:

if ! examplecommand arg1 arg2 ...; then
    #code block
fi

without any brackets.

Upvotes: 5

phil294
phil294

Reputation: 10902

What am I doing wrong?

$(...) holds the value, not the exit status, that is why this approach is wrong. However, in this specific case, it does indeed work because sysa will be printed which makes the test statement come true. However, if ! [ $(true) ]; then echo false; fi would always print false because the true command does not write anything to stdout (even though the exit code is 0). That is why it needs to be rephrased to if ! grep ...; then.

An alternative would be cat /etc/passwd | grep "sysa" || echo error. Edit: As Alex pointed out, cat is useless here: grep "sysa" /etc/passwd || echo error.

Found the other answers rather confusing, hope this helps someone.

Upvotes: 11

SDsolar
SDsolar

Reputation: 2725

Here is an answer by way of example:

In order to make sure data loggers are online a cron script runs every 15 minutes that looks like this:

#!/bin/bash
#
if ! ping -c 1 SOLAR &>/dev/null
then
  echo "SUBJECT:  SOLAR is not responding to ping" | ssmtp [email protected]
  echo "SOLAR is not responding to ping" | ssmtp [email protected]
else
  echo "SOLAR is up"
fi
#
if ! ping -c 1 OUTSIDE &>/dev/null
then
  echo "SUBJECT:  OUTSIDE is not responding to ping" | ssmtp [email protected]
  echo "OUTSIDE is not responding to ping" | ssmtp [email protected]
else
  echo "OUTSIDE is up"
fi
#

...and so on for each data logger that you can see in the montage at http://www.SDsolarBlog.com/montage


FYI, using &>/dev/null redirects all output from the command, including errors, to /dev/null

(The conditional only requires the exit status of the ping command)

Also FYI, note that since cron jobs run as root there is no need to use sudo ping in a cron script.

Upvotes: 3

Kusalananda
Kusalananda

Reputation: 15633

On Unix systems that supports it (not macOS it seems):

if getent passwd "$username" >/dev/null; then
    printf 'User %s exists\n' "$username"
else
    printf 'User %s does not exist\n' "$username"
fi 

This has the advantage that it will query any directory service that may be in use (YP/NIS or LDAP etc.) and the local password database file.


The issue with grep -q "$username" /etc/passwd is that it will give a false positive when there is no such user, but something else matches the pattern. This could happen if there is a partial or exact match somewhere else in the file.

For example, in my passwd file, there is a line saying

build:*:21:21:base and xenocara build:/var/empty:/bin/ksh

This would provoke a valid match on things like cara and enoc etc., even though there are no such users on my system.

For a grep solution to be correct, you will need to properly parse the /etc/passwd file:

if cut -d ':' -f 1 /etc/passwd | grep -qxF "$username"; then
    # found
else
    # not found
fi

... or any other similar test against the first of the :-delimited fields.

Upvotes: 2

Rony
Rony

Reputation: 1734

I think it can be simplified into:

grep sysa /etc/passwd || {
    echo "ERROR - The user sysa could not be looked up"
    exit 2
}

or in a single command line

$ grep sysa /etc/passwd || { echo "ERROR - The user sysa could not be looked up"; exit 2; }

Upvotes: 39

Related Questions