grep a pattern and output non-matching part of line

13,939

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:

  1. /$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.
  2. /s/: This says you will be doing a substitution
  3. /$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.
  4. //: This is what you're substituting for $PAT. It is null. Therefore, you're deleting $PAT from the line.
  5. /p: This final p 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?

Share:
13,939

Related videos on Youtube

Dennis
Author by

Dennis

Updated on June 04, 2022

Comments

  • Dennis
    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
    Dennis almost 13 years
    thanks, 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.
    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 pipe grep through sed and then get the exit status of grep 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 for grep taken from STDOUT?
  • Dennis
    Dennis almost 13 years
    yeah 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
    Dennis almost 13 years
    My 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
    Admin over 11 years
    It 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.
    David W. over 11 years
    Ask, and ye shall receive. See explanation above.