user1118764
user1118764

Reputation: 9835

Checking if output of a command contains a certain string in a shell script

I'm writing a shell script, and I'm trying to check if the output of a command contains a certain string. I'm thinking I probably have to use grep, but I'm not sure how. Does anyone know?

Upvotes: 228

Views: 339401

Answers (5)

Ehsan
Ehsan

Reputation: 4291

A clean if/else conditional shell script:

if ./somecommand | grep -q 'some string'
then
  echo "exists"
else
  echo "doesn't exist"
fi

Upvotes: 18

F1Linux
F1Linux

Reputation: 4373

SHORT ANSWER

All the above (very excellent) answers all assume that grep can "see" the output of the command, which isn't always true:

SUCCESS can be sent to STDOUT while FAILURE to STDERR.

So depending on which direction you test, your grep can fail. That's to say that if you are testing for the case of FAILURE you must redirect the output of the command to STDOUT using 2>&1 in such a case as this.

LONGER ANSWER w/ PROOFS

I had what I thought was a very simple test in a bash script using grep and it kept failing. Much head scratching followed. Use of set -x in my script revealed that the variable was empty! So I created the following test to understand how things were breaking.

NOTE: iscsiadm is a Linux tool from the "open-iscsi" package used to connect/disconnect a host to SAN storage. The command iscsiadm -m session is used to show if any LUN connections are established):

#!/bin/bash

set -x

TEST1=$(iscsiadm -m session)
TEST2=$(iscsiadm -m session 2>&1)
echo
echo 'Print TEST1'
echo $TEST1
echo
echo 'Print TEST2'
echo $TEST2
echo

If a LUN WAS connected, BOTH variables were successfully populated with values:

Print TEST1
tcp: [25] 192.168.X.XX:3260,1 iqn.2000-01.com.synology:ipdisk.Target-LUN1 (non-flash) tcp: [26] 192.168.X.XX:3260,1 iqn.2000-01.com.synology:storagehost.Target-LUN1 (non-flash)

Print TEST2
tcp: [25] 192.168.X.XX:3260,1 iqn.2000-01.com.synology:ipdisk.Target-LUN1 (non-flash) tcp: [26] 192.168.X.XX:3260,1 iqn.2000-01.com.synology:storagehost.Target-LUN1 (non-flash)

However, if a LUN WASN'T connected, iscsiadm sent the output to STDERR, and only the "TEST2" variable was populated where we had redirected to STDOUT using 2>&1; "TEST1" variable which had no redirection to STDOUT was empty:

iscsiadm: No active sessions.

Print TEST1


Print TEST2
iscsiadm: No active sessions.

CONCLUSION

If you have a funky, half-broken- works in one direction but not the other- situation such as this, try the above test replacing iscsiadm with your own command and you should get the proper visibility to rewrite your test to work correctly.

Upvotes: 10

mat
mat

Reputation: 13353

Testing $? is an anti-pattern.

if ./somecommand | grep -q 'string'; then
  echo "matched"
fi

Upvotes: 260

Noam Manos
Noam Manos

Reputation: 16971

Another option is to check for regular expression match on the command output.

For example:

[[ "$(./somecommand)" =~ "sub string" ]] && echo "Output includes 'sub string'"

Upvotes: 19

perreal
perreal

Reputation: 97948

Test the return value of grep:

./somecommand | grep 'string' &> /dev/null
if [ $? == 0 ]; then
   echo "matched"
fi

which is done idiomatically like so:

if ./somecommand | grep -q 'string'; then
   echo "matched"
fi

and also:

./somecommand | grep -q 'string' && echo 'matched'

Upvotes: 183

Related Questions