get output and return value of grep in single operation in bash
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.
- I put
grep
output to theOUTPUT
variable - 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. - Then, check
line_count
in thecase
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
Related videos on Youtube
Comments
-
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 about 7 years
-
Admin about 7 yearsI'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 about 7 yearsI need the output and return code. $? Might do the job
-
Admin about 7 years@ilansch I added another answer that should satisfy your requirements.
-
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 about 7 yearsYes. In 2 variables. Cant i modify a local variable during the execution?
-
-
pfnuesel about 7 yearsWhy the downvote?
-
Admin about 2 yearsI’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 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 about 2 years@Scott, can you clarify what doesn't work?
-
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 about 2 yearsThe question is a bit muddled, but the OP seems to want the
OUTPUT
variable to containsockname: 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 theoutput
variable to2
. -
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 callcountMatches
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 ifIFS
is set to something weird, and even$#
,$!
and$?
can suffer from word splitting if they aren’t quoted.