tags:

views:

357

answers:

5

Okay, so I'm learning Bash, and there's that exercise;

"Write a script that checks every ten seconds if the user 'user000' is logged in."

My idea is to grep a who, but I don't know how to incorporate this into a script. I tried things like

if [ `who | grep "user000"` ] then things

but it returns the matched lines with grep, not true/false.

A: 

You can do

who | grep "user000" > /dev/null  2>&1
# You can use "-q" option of grep instead of redirecting to /dev/null 
# if your grep support it. Mine does not.
if [ "$?" -eq "0" ]
then ...

This uses $? - a Shell variable which stores the return/exit code of the last command that was exected. grep exits with return code "0" on success and non-zero on failure (e.g. no lines found returns "1" ) - a typical arrangement for a Unix command, by the way.

DVK
Dennis Williamson
That's cause I used csh refirection instead of sh redirection by force of habit - didn't do anything in bourne in ages :)
DVK
And the reason for down-voting is???
DVK
+3  A: 

You want grep -q. That's "quiet mode"; just sets status based on whether there were any matches, doesn't output anything. So:

if who | grep -q "user000"; then things; fi
chaos
FYI - Solaris's `grep` does not support `-q`
DVK
DVK: Too bad. POSIX grep specifies `-q' since 1997: http://www.opengroup.org/onlinepubs/7990989775/xcu/grep.htmlAlso, drop the brackets. It's the shell equivalent of if (var == true) {}
guns
Probably want to throw a "|cut -d1 -b' '" in there and use "grep '^user000$'". This will avoid false positives when 'user0001' logs in.
Stephen Paul Lesniewski
Well, I meant drop the brackets and the backticks. The shell will evaluate the exit value of the command transparently.
guns
guns
guns - you know, some people actually care about portability. And some people are not into righteousness of using One True XXX (in this case XXX=variant of Unix)
DVK
@DVK: What's not portable about my suggestions? It's classic sh as far as I know. I agree with you about not using `grep -q`, if that's what you're referring to.
guns
@DVK: Oh I see. I didn't mean "screw solaris", but "that's unfortunate".
guns
A: 

It's probably not the most elegant incantation, but I tend to use:

if [ `who | grep "user000" | wc -l` = "1" ]; then ....
the_mandrill
why not use 'who | grep -c user000' ?
innaM
What if the user is logged in more than once?
Dennis Williamson
@Manni: hadn't thought of the -c flag to grep. Is that Posix though, or an extension?@Dennis: does `who` list one mention per login shell?
the_mandrill
I'm ssh'd into a server a couple of time, plus a couple of xterms, plus the gdm login or whatever so my name appears five times in who right now.
Dennis Williamson
@the_mandrill: since -c also works on ancient solaris boxes, I guess it's Posix.
innaM
A: 

Most answers have the right idea, but really you want to drop all output from grep, including errors. Also, a semicolon is required after the ] for an if:

if who | grep 'user000' >/dev/null 2>&1; then
    do things
fi

If you are using GNU grep, you can use the -s and -q options instead:

if who | grep -sq 'user000'; then
    do things
fi

EDIT: dropped brackets; if only needs brackets for comparison ops

Walter Mundt
You can duplicate file descriptors and shorten the redirection spec.
Dennis Williamson
Semicolon is only required when _then_ appears on the same line. When _then_ is on the following line, it is not needed.
bstpierre
LB
+1  A: 

If you're testing the exit code of a pipe or command in a if or while, you can leave off the square brackets and backticks (you should use $() instead of backticks anyway):

if who | grep "user000" > /dev/null 2>&1
then
  things-to-do
fi
Dennis Williamson
You can also leave off the quotes around user000.
Idelic