123

As a part of this script, I need to be able to check if the first argument given matches the first word of file. If it does, exit with an error message; if it doesn't, append the arguments to the file. I understand how to write the if statement, but not how to use grep within a script. I understand that grep will look something like this

grep ^$1 schemas.txt

I feel like this should be much easier than I am making it.

I'm getting an error "too many arguments" on the if statement. I got rid of the space between grep -q and then got an error binary operator expected.

if [ grep -q ^$1 schemas.txt ]
then
        echo "Schema already exists. Please try again"
        exit 1
else
        echo "$@" >> schemas.txt
fi
164

grep returns a different exit code if it found something (zero) vs. if it hasn't found anything (non-zero). In an if statement, a zero exit code is mapped to "true" and a non-zero exit code is mapped to false. In addition, grep has a -q argument to not output the matched text (but only return the exit status code)

So, you can use grep like this:

if grep -q PATTERN file.txt; then
    echo found
else
    echo not found
fi

As a quick note, when you do something like if [ -z "$var" ]…, it turns out that [ is actually a command you're running, just like grep. On my system, it's /usr/bin/[. (Well, technically, your shell probably has it built-in, but that's an optimization. It behaves as if it were a command). It works the same way, [ returns a zero exit code for true, a non-zero exit code for false. (test is the same thing as [, except for the closing ])

  • Why doesn't the if statement need the brackets? I have it working without, but don't understand why. Can I still nest it without the brackets? – Lauren Sep 18 '12 at 18:47
  • @Lauren did you miss the quick note? [ is not part of the if syntax, it's (conceptually) a command you're running, just like grep – derobert Sep 18 '12 at 19:06
  • Ok. I read it, just having trouble understanding it. So, since grep -q itself is returning a true/false value, it is unnecessary and problematic to use the command [ also? – Lauren Sep 18 '12 at 19:19
  • 2
    @Lauren You don't use grep inside of [, you use one or the other, depending on what condition you want to check. (You can use any command inside an if, btw, if just checks exit code.) … well, I guess you probably could come up with a reason to use grep inside [, but that'd be a fairly complicated script, and its not a normal thing to do. – derobert Sep 18 '12 at 19:21
  • 2
    FYI, run ls -l /usr/bin/\[ and man [ to see that [ is a program like any other, it just looks like a syntactic element - this should make it obvious and easier to understand. (for convenience, [ is also a built-in in bash, dash, and others - but it's still a command). also try type -all [ in bash. – cas Sep 18 '12 at 22:56
45

Another simple way is to use grep -c.

That outputs (not return as exit code), the number of lines that match the pattern, so 0 if there's no match or 1 or more if there's a match.

So, if you wanted to check that the pattern is matched 3 or more times, you would do:

if [ "$(grep -c "^$1" schemas.txt)" -ge 3 ]; then
  ...
  • 16
    More precisely, it will output 1 if found only once. To output 1 regardless the amount of found matches use grep -cim1 instead. – manatwork Apr 29 '13 at 10:26
  • This method can also be used to distinguish between grep error and grep 'pattern found 0 times'. (although not with the exact if statement used, i think a variable is required) – Evan Benn Apr 3 at 5:27
2

I know I am late for this, but I love this short version:

grep -q ^$1 schemas.txt && echo "Schema already exists. Please try again" || echo "$@" >> schemas.txt
0

If we want to catch the first word of a file we need do add -zw to grep

if grep -qzw "^$1" file
then 
   ... 
else 
   ... 
fi

Without -z we get the first word of a line. Without -w we get partial words.

-1

If you want to use it with square brackets, you can execute the below

if [ `grep -q PATTERN file.txt` ]; then
    echo found
else
    echo not found

This Logic works for all commands, Just place your commands inside backtick (the button above tab or to the down of Esc button or to the left of 1 button)

  • 1
    You'd need to quote the `grep -q PATTERN file.txt`, otherwise the split+glob operator is applied and that would cause problem for any output that contains characters of $IFS or wildcard characters. More generally, [ "`cmd`" ] would return true if cmd outputs at least one non-empty line on stdout (with potential problems if it outputs NUL bytes). That means the shell will have to store the whole output in memory and wait for it to finish. Using if cmd | grep -q . instead may be preferable in that regard. – Stéphane Chazelas Aug 24 '16 at 13:01
  • This command would make no sense at all. The purpose of the -q switch is to suppress grep's output. You are saying: Check for PATTERN in file.txt, suppress any output, then set the return status according to whether PATTERN was found. Then, ignore the return status, take the command output (which we forced to be empty), apply word splitting and file glob expansion (resulting in no arguments at all), then run the [ (a.k.a. test) command with exactly one argument--namely, ]--and then, since that will result in an error, echo "not found". @StéphaneChazelas, did I miss something? – Wildcard Sep 16 '16 at 22:51
  • 1
    @Wildcard, you're right, I apparently overlooked the -q. That comment would have made sense for [ `grep PATTERN file.txt ` ], but as hinted in the comment, [ "`grep -n PATTERN file.txt`" ] would be better if PATTERN may match only empty lines. Though here of course it's if grep -q PATTERN file.txt you want. – Stéphane Chazelas Sep 17 '16 at 6:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.