regexp (sed) suppress "no match" output

11,917

Solution 1

sed by default prints all lines.

What you want to do is

/patt/!d;s//repl/

IOW delete lines not matching your pattern, and if they match, extract particular element from it, giving capturing group number for instance. In your case it will be:

sed -e '/^.*\(.\)\([0-9][0-9]\)\1.*$/!d;s//\2/'

You can also use -n option to suppress echoing all lines. Then line is printed only when you explicitly state it. In practice scripts using -n are usually longer and more cumbersome to maintain. Here it will be:

sed -ne 's/^.*\(.\)\([0-9][0-9]\)\1.*$/\2/p'

There is also grep, but your example shows, why sed is sometimes better.

Solution 2

Perhaps you can use egrep -o?

input.txt:

blooody
aaaa
bbbb
odor
qqqq

E.g.

sehe@meerkat:/tmp$ egrep -o o+ input.txt 
ooo
o
o
sehe@meerkat:/tmp$ egrep -no o+ input.txt 
1:ooo
4:o
4:o

Of course egrep will have slightly different (better?) regex syntax for advanced constructs (back-references, non-greedy operators). I'll let you do the translation, if you like the approach.

Share:
11,917

Related videos on Youtube

yPhil
Author by

yPhil

My music https://exode.me/accounts/yphil/ My code https://framagit.org/yphil http://bitbucket.org/yphil Pay me a beer? Why sure, thanks! https://liberapay.com/yPhil/donate

Updated on May 16, 2020

Comments

  • yPhil
    yPhil almost 4 years

    I'm stuck on that and can't wrap my head around it: How can I tell sed to return the value found, and otherwise shut up?

    It's really beyond me: Why would sed return the whole string if he found nothing? Do I have to run another test on the returned string to verify it? I tried using "-n" from the (very short) man page but it effectively suppresses all output, including matched strings.

    This is what I have now :

    echo plop-02-plop | sed -e 's/^.*\(.\)\([0-9][0-9]\)\1.*$/\2/'
    

    which returns 02 (and that is fine and dandy, thank you very much), but:

    echo plop-02plop | sed -e 's/^.*\(.\)\([0-9][0-9]\)\1.*$/\2/'
    

    returns plop-02plop (when it should return this = "" nothing! Dang, you found nothing so be quiet! For crying out loud !!)

    I tried checking for a return value, but this failed too ! Gasp !!

    $ echo plop-02-plop | sed -e 's/^.*\(.\)\([0-9][0-9]\)\1.*$/\2/' ; echo $?
    02
    0
    $ echo plop-02plop | sed -e 's/^.*\(.\)\([0-9][0-9]\)\1.*$/\2/' ; echo $?
    plop-02plop
    0
    $
    

    This last one I cannot even believe. Is sed really the tool I should be using? I want to extract a needle from a haystack, and I want a needle or nothing..?

    • Jonathan Leffler
      Jonathan Leffler almost 13 years
      As you have discovered, sed is doing as you request; it is a stream editor and prints its input to its output as modified by the script. Your non-matching case didn't change the data, so what was echoed was your input - this is the correct behaviour for sed. And the answer to suppressing output is to use -n and then add an explicit p when you want something printed.
  • yPhil
    yPhil almost 13 years
    I'll be damned, it works. Thank you very much sir. @sehe Thanks, I will check grep.
  • Jonathan Leffler
    Jonathan Leffler almost 13 years
    You can shorten the -n version to: sed -ne 's/^.*\(.\)\([0-9][0-9]\)\1.*$/\2/p' which is shorter than your version without -n.
  • przemoc
    przemoc almost 13 years
    @Jonathan You're absolutely right. In this particular case -n is shorter indeed. I should've written -n way as you suggested from the beginning, but it somehow slipped my mind. Pretty embarrassing. ;)
  • yPhil
    yPhil almost 13 years
    @Jonathan @przemoc And what would one do to get the opposite ? That is returning the string without the matched bit ?
  • przemoc
    przemoc almost 13 years
    @xaccrocheur Remove ! in my boilerplate (and possibly s/// command too; depends on whether you want to further modify it or not). For -n way it would be /patt/!p.
  • Jonathan Leffler
    Jonathan Leffler almost 13 years
    @xaccrocheur: sed -ne 's/^\(.*\)\(.\)[0-9][0-9]\1\(.*\)$/\1\2\2\3/p' - untested
  • przemoc
    przemoc almost 13 years
    @xaccrocheur I misread your question. @Jonathan seems almost right, but used wrong backreference in pattern (should be \2 instead of \1).
  • lilalinux
    lilalinux over 2 years
    -ne ... /p is really convenient