Checking if output of a command contains a certain string in a shell script
BashShellGrepBash Problem Overview
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?
Bash Solutions
Solution 1 - Bash
Testing $?
is an anti-pattern.
if ./somecommand | grep -q 'string'; then
echo "matched"
fi
Solution 2 - Bash
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'
Solution 3 - Bash
Another option is to check for regular expression match on the command output.
For example:
[[ "$(./somecommand)" =~ "sub string" ]] && echo "Output includes 'sub string'"
Solution 4 - Bash
A clean if/else conditional shell script:
if (ls | grep '$1') then echo "exists" else echo "doesn't exist" fi
Solution 5 - Bash
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.