grep a pattern and output non-matching part of line
Solution 1
How about using a combination of grep
, sed
and $PIPESTATUS
to get the correct exit-status?
$ echo Humans are not proud of their ancestors, and rarely invite
them round to dinner | grep dinner | sed -n "/dinner/s/dinner//p"
Humans are not proud of their ancestors, and rarely invite them round to
$ echo $PIPESTATUS[1]
0[1]
The members of the $PIPESTATUS
array hold the exit status of each respective command executed in a pipe. $PIPESTATUS[0]
holds the exit status of the first command in the pipe, $PIPESTATUS[1]
the exit status of the second command, and so on.
Solution 2
You could use sed
:
$ sed -n "/$PAT/s/$PAT//p" $file
The only problem is that it'll return an exit code of 0 as long as the pattern is good, even if the pattern can't be found.
Explanation
The -n
parameter tells sed
not to print out any lines. Sed's default is to print out all lines of the file. Let's look at each part of the sed
program in between the slashes. Assume the program is /1/2/3/4/5
:
/$PAT/
: This says to look for all lines that matches pattern$PAT
to run your substitution command. Otherwise,sed
would operate on all lines, even if there is no substitution./s/
: This says you will be doing a substitution/$PAT/
: This is the pattern you will be substituting. It's$PAT
. So, you're searching for lines that contain$PAT
and then you're going to substitute the pattern for something.//
: This is what you're substituting for$PAT
. It is null. Therefore, you're deleting$PAT
from the line./p
: This finalp
says to print out the line.
Thus:
- You tell
sed
not to print out the lines of the file as it processes them. - You're searching for all lines that contain
$PAT
. - On these lines, you're using the
s
command (substitution) to remove the pattern. - You're printing out the line once the pattern is removed from the line.
Solution 3
Your $tags will never have a value because you send it to /dev/null. Besides from that little problem, there is no input to grep.
echo hello |grep "^he" -q ;
ret=$? ;
if [ $ret -eq 0 ];
then
echo there is he in hello;
fi
a successful return code is 0.
...here is 1 take at your 'problem':
pat="most of ";
data="The apples are ripe. I will use most of them for jam.";
echo $data |grep "$pat" -q;
ret=$?;
[ $ret -eq 0 ] && echo $data |sed "s/$pat//"
The apples are ripe. I will use them for jam.
... exact same thing?:
echo The apples are ripe. I will use most of them for jam. | sed ' s/most\ of\ //'
It seems to me you have confused the basic concepts. What are you trying to do anyway?
Related videos on Youtube
Dennis
Updated on June 04, 2022Comments
-
Dennis almost 2 years
I know it is possible to invert grep output with the
-v
flag. Is there a way to only output the non-matching part of the matched line? I ask because I would like to use the return code of grep (which sed won't have). Here's sort of what I've got:tags=$(grep "^$PAT" >/dev/null 2>&1) [ "$?" -eq 0 ] && echo $tags
-
Dennis almost 13 yearsthanks, but it would be nice if I could get the exit code. I guess sed never implemented exit codes because it didn't really make sense.
-
David W. almost 13 years@Dennis Hodapp: Sed doesn't give you an exit status other than zero because it works even if it didn't edit anything. You could simply do an
if [ -z $tags ]
to test if$tag
was set. Or, you could pipegrep
throughsed
and then get the exit status ofgrep
via the$PIPESTATUS
environment variable since it's possible that grep will find something, but there won't be any tag set. I could give a bit more info if I knew what you needed to do. In your original post,grep
has no file name on the command line. Is the input forgrep
taken from STDOUT? -
Dennis almost 13 yearsyeah that was bad on my part. I think I copied it in incorrectly, but that's inconsequential. The whole point is to use grep to find a pattern. I want the return code, and then the part of the line not matched. As I look at it more, there is really no point except to try to write less code (one grep command). Fredrik above seems to have solved my problem in an interesting way but yours also works.
-
Dennis almost 13 yearsMy question wasn't very good, and I copied wrong. I forgot to add the input file which was a file with multiple lines. Your answer (with comment) is also exactly what I had in mind. I can't award the answer to 2 people though.
-
Admin over 11 yearsIt would be nice if you could explain what the general form of the above sed syntax is. i.e., what the hell does
/$pat/s/$pat//p
mean in sed-speak? How does application of this syntax solve OP's question? -
David W. over 11 yearsAsk, and ye shall receive. See explanation above.