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?
-
Does the command need to keep running after generating the output string you're looking for, or can it be immediately closed at that time? (Your two answers differ in terms of their semantics in this respect). – Charles Duffy Mar 30 '16 at 15:49
5 Answers
Testing $?
is an anti-pattern.
if ./somecommand | grep -q 'string'; then
echo "matched"
fi
-
If by any chance you only want to test a fixed string, add **F** and **x** options: `grep -Fxq` **F** stands for fixed (not interpreted) and **x** for the whole line – Erdal G. Dec 11 '17 at 11:51
-
10
-
3@VitalyZdanevich I assume because it's not robust against concurrency. – Konrad Reiche Oct 16 '18 at 02:54
-
3@VitalyZdanevich, for one, testing `$?` doesn't set the preceding commands as "checked" for purposes of `set -e` or the `ERR` trap, so your program can exit in cases where you want it to simply return down the intentionally-false path later. For another, `$?` is volatile global state -- it's easy to throw away its value by accident. For example, if you add a line of logging like `echo "Exit status is $?"`, the new value in `$?` becomes the exit status of `echo`. – Charles Duffy Mar 12 '19 at 15:40
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'

- 94,503
- 21
- 155
- 181
-
3This code doesn't work with all POSIX shells: The POSIX standard only requires `=` to be a comparison operator, not `==`; see http://pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html – Charles Duffy Mar 30 '16 at 15:44
-
6Also, `grep 'string' &>/dev/null` is both non-POSIX compliant and much slower to execute (if `string` appears early in a long output stream) than `grep -q string`. [The caveat there is if you want to be sure `somecommand` keeps running even after emitting `string`, in which case using `grep -q` -- by closing its stdin and exiting after the first instance of `string` is seen -- can be counterproductive]. (Re: "non-POSIX-compliant", `&>` is an extension -- see http://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_07 describing the POSIX-mandated redirection support). – Charles Duffy Mar 30 '16 at 15:46
-
1Would help if it was explained why that works/what each parameter does, to encourage full understanding of the syntax – redfox05 Oct 17 '17 at 19:52
-
See also [Why is testing “$?” to see if a command succeeded or not, an anti-pattern?](https://stackoverflow.com/questions/36313216/why-is-testing-to-see-if-a-command-succeeded-or-not-an-anti-pattern) – tripleee Dec 15 '20 at 12:05
-
-
@alper, it can for sure but the answer depends on the exact problem. ex, `echo "string" | grep "st.*"` already prints the result. – perreal Mar 30 '21 at 20:52
-
Will check the output of the script or check the contents of the /dev/null file? What if I want to test the output, but also write to a separate file? – Talos Potential Sep 13 '22 at 21:46
-
@Talos Then `grep whatever && echo "smurfs" >gargamel.txt` without the `-q` if you want to see the output from `grep` – tripleee May 04 '23 at 16:56
Another option is to check for regular expression match on the command output.
For example:
[[ "$(./somecommand)" =~ "sub string" ]] && echo "Output includes 'sub string'"

- 15,216
- 3
- 86
- 85
A clean if
/else
conditional shell script:
if ./somecommand | grep -q 'some string'
then
echo "exists"
else
echo "doesn't exist"
fi
-
This seems to be a restatement of earlier answers, except the trivially obvious `else` addition. – tripleee May 04 '23 at 17:08
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.

- 3,580
- 3
- 25
- 24
-
3That was the missing piece I needed. Commands like resize2fs need it (2>&1). Thanks for clarifying! – FalloutBoy Dec 28 '21 at 19:39
-
1@FalloutBoy No prob; happy to help. This site has saved me tons of wasted cycles, so it seems right we all take a moment to contribute something back- – F1Linux Dec 28 '21 at 20:06