get output and return value of grep in single operation in bash

101,877

Solution 1

You can use

output=$(grep -c 'name' inputfile)

The variable output will then contain the number 0, 1, or 2. Then you can use an if statement to execute different things.

Solution 2

This is fairly simple:

OUTPUT=$(pfiles "$1" 2> /dev/null | grep peername)
grep_return_code=$?

If a $(…) command substitution is assigned to a variable, $? will get the return code from the last command in the $(…).  And, of course, you don’t need to refer to $? explicitly; you can do things like

if OUTPUT=$(pfiles "$1" 2> /dev/null | grep peername)
then
    # the rest of the script
                ︙
fi

or

if ! OUTPUT=$(pfiles "$1" 2> /dev/null | grep peername)
then
    exit
fi
# the rest of the script

This approach is useful in situations where the output of the command and its return code (a.k.a. exit status) are uncorrelated.  But, for grep, they are highly correlated: If it produced output, it succeeded.  If it didn’t produce output, it failed.  So why not just test the output ?

OUTPUT=$(pfiles "$1" 2> /dev/null | grep peername)
if [ "$OUTPUT" ]
then
    # the rest of the script
                ︙
fi

or

OUTPUT=$(pfiles "$1" 2> /dev/null | grep peername)
if [-z "$OUTPUT" ]
then
    exit
fi
# the rest of the script

P.S. You should always quote your shell variable references (e.g., "$1") unless you have a good reason not to, and you’re sure you know what you’re doing.

Solution 3

Try this code, I feel, it doing what you want.

  1. I put grep output to the OUTPUT variable
  2. I think, you don't need grep exit status as boolean value. It is 0 or 1, and it doesn't suit to your task. You need amount of lines - 0, 1, 2, etc. Therefore, count lines in the OUTPUT variable and put this number to the second variable - line_count. We will have two variables in the result. First with grep output, second with amount of lines.
  3. Then, check line_count in the case statement and do needed action.

Usage: ./switching_by_grep_result.sh your_file.txt

#!/bin/bash

# your code
OUTPUT=$(pfiles $1 2> /dev/null | grep name) # $1 Process Id

# count lines in the OUTPUT variable by using 'grep -c'
line_count=$(echo -n "$OUTPUT" | grep -c '^')

# checks lines count in here and invokes needed script or exit.
# if 0 lines - exit
# if 1 lines - invoke A
# if any other number of lines - invoke B
case $line_count in  
    0) echo 'exit'
    ;;  
    1) echo 'A() script invoking here'
    ;;  
    *) echo 'B() script invoking here'
    ;;  
esac

Solution 4

If you need the result of grep, you can not use the -c flag as outlined in the other answer. What you can do, though, is running twice, once with -c flag to get the number of matches and one without -c flag, to see the matches. However, this can be very inefficient, depending on the size of your input file.

You can do something like this:

Content of input:

The first line is foo
I have a drink at the bar
The third line is foo again

Content of script:

#!/usr/bin/env bash

countMatches(){
    echo Searching for "${1}"
    result=$(grep "${1}" input)
    if [ "$?" -ne 0 ]; then
        echo No match found
        echo
        exit 1
    fi

    if [ $(echo "${result}" | wc -l) -eq 1 ]; then
        echo 1 match found:
        echo "${result}"
        echo
    else
        echo 2 matches found:
        echo "${result}"
        echo
    fi
}

countMatches foo
countMatches bar
countMatches baz

And here's the output when you invoke the script:

Searching for foo
2 matches found:
The first line is foo
The third line is foo again

Searching for bar
1 match found:
I have a drink at the bar

Searching for baz
No match found
Share:
101,877

Related videos on Youtube

ilansch
Author by

ilansch

if needed find me at: ilan84 at gmail dot com

Updated on September 18, 2022

Comments

  • ilansch
    ilansch almost 2 years

    I am writing a bash script; I execute a certain command and grep.

    pfiles $1 2> /dev/null | grep name # $1 Process Id
    

    The response will be something like:

    sockname: AF_INET6 ::ffff:10.10.50.28  port: 22
    peername: AF_INET6 ::ffff:10.16.6.150  port: 12295
    

    The response can be no lines, 1 line, or 2 lines.
    In case grep returns no lines (grep return code 1), I abort the script; if I get 1 line I invoke A() or B() if more than 1 line. grep's return code is 0 when the output is 1-2 lines.

    grep has return value (0 or 1) and output.
    How can I catch them both ? If I do something like:

    OUTPUT=$(pfiles $1 2> /dev/null | grep peername)
    

    Then variable OUTPUT will have the output (string); I also want the boolean value of grep execution.

    • Admin
      Admin about 7 years
    • Admin
      Admin about 7 years
      I'm not sure if I understood the question. Do you need the output from grep at all? Do you need the return value? Would it be enough to just count the matchs, as per my answer below?
    • Admin
      Admin about 7 years
      I need the output and return code. $? Might do the job
    • Admin
      Admin about 7 years
      @ilansch I added another answer that should satisfy your requirements.
    • Admin
      Admin about 7 years
      "variable OUTPUT will have the output (string); I also want the boolean value of grep execution." Where this two values should be stored (boolean value and grep output)? In the OUTPUT variable both, each on its own line? Just interesting, what you wanted.
    • Admin
      Admin about 7 years
      Yes. In 2 variables. Cant i modify a local variable during the execution?
  • pfnuesel
    pfnuesel about 7 years
    Why the downvote?
  • Admin
    Admin about 2 years
    I’m wondering how this answer ever got any up votes when it does not do what the question asks for — capture the output of grep in a variable.
  • Admin
    Admin about 2 years
    (1) You don’t need any of those curly braces in parameter expansions (${1} and ${result}) — quotes alone are enough …  (2) … and you should use quotes for "$?".  (3) grep, like a few other programs, can exit with a status of 2 for system-level errors (like failure to open or read a file).  If you want to test for failure of a program, you should test for "$?" -ne 0.
  • Admin
    Admin about 2 years
    @Scott, can you clarify what doesn't work?
  • Admin
    Admin about 2 years
    @Scott I fixed point (2) and (3). As for (1), the curly braces are not needed but don't hurt either, it's a matter of style. One could even argue that the quotes around ${1} or $? are not needed either since it's always one word. Thanks for proofreading and feel free to directly edit my posts!
  • Admin
    Admin about 2 years
    The question is a bit muddled, but the OP seems to want the OUTPUT variable to contain sockname: AF_INET6 ::ffff:10.10.50.28  port: 22(newline)peername: AF_INET6 ::ffff:10.16.6.150  port: 12295. As your answer says, it only sets the output variable to 2.
  • Admin
    Admin about 2 years
    (4) It’s not valid to say that $1 doesn’t need to be quoted “since it's always one word” just because you plan to use arguments that don’t contain spaces or glob characters.  Somebody else might want to call countMatches with an argument like 'Local Address'. (5) As Stéphane Chazelas pointed out in Security implications of forgetting to quote a variable in bash/POSIX shells, you should write scripts that work correctly even if IFS is set to something weird, and even $#, $! and $? can suffer from word splitting if they aren’t quoted.