24

In bash, I want to say "if a file doesn't contain XYZ, then" do a bunch of things. The most natural way to transpose this into code is something like:

if [ ! grep --quiet XYZ "$MyFile" ] ; then
   ... do things ...
fi

But of course, that's not valid Bash syntax. I could use backticks, but then I'll be testing the output of the file. The two alternatives I can think of are:

grep --quiet XYZ "$MyFile"
if [ $? -ne 0 ]; then
   ... do things ...
fi

And

grep --quiet XYZ "$MyFile" ||
   (  ... do things ...
   )

I kind of prefer the second one, it's more Lispy and the || for control flow isn't that uncommon in scripting languages. I can see arguments for the first one too, although when the person reads the first line, they don't know why you're executing grep, it looks like you're executing it for it's main effect, rather than just to control a branch in script.

Is there a third, more direct way which uses an if statement and has the grep in the condition?

1

3 Answers 3

46

Yes there is:

if grep --quiet .....
then
    # If grep finds something
fi

or if the grep fails

if ! grep --quiet .....
then
    # If grep doesn't find something
fi
Sign up to request clarification or add additional context in comments.

4 Comments

D'oh! Thanks. In my defense, I haven't seen that in any tutorials, even ones that talk about checking the exit code of a command.
[ is kind of an alias for test (which also requires ]). So if [ ... ] is equivalent to if test ...
What if you want to test multiple conditions, one of which is exit status of a command? As in: if [[ $OS == "windows" && command-exit-status==0 ]]; ... ? I can run the command first and save $? of course, but I'd like the shortcut && behavior so it doesn't run the command unless $OS==windows. Any good ideas?
@GaryO: You could write it like if [[ $OS == "windows" ]] && command; then or if even without the if like [[ $OS == "windows" ]] && command && echo "All ok"
14

You don't need the [ ] (test) to check the return value of a command. Just try:

if ! grep --quiet XYZ "$MyFile" ; then

Comments

3

This is a matter of taste since there obviously are multiple working solutions. When I deal with a problem like this, I usually apply wc -l after grep in order to count the lines that match. Then you have a single integer number that you can evaluate within a test condition. If the question only is whether there is a match at all (the number of matching lines does not matter), then applying wc probably is OTT and evaluation of grep's return code seems to be the best solution:

Normally, the exit status is 0 if selected lines are found and 1 otherwise. But the exit status is 2 if an error occurred, unless the -q or --quiet or --silent option is used and a selected line is found. Note, however, that POSIX only mandates, for programs such as grep, cmp, and diff, that the exit status in case of error be greater than 1; it is therefore advisable, for the sake of portability, to use logic that tests for this general condition instead of strict equality with 2.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.