Reputation: 9835
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
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
Reputation: 4373
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.
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.
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
Reputation: 13353
Testing $?
is an anti-pattern.
if ./somecommand | grep -q 'string'; then
echo "matched"
fi
Upvotes: 260
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
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