regexp (sed) suppress "no match" output
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.
Related videos on Youtube
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, 2020Comments
-
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 almost 13 yearsAs 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 forsed
. And the answer to suppressing output is to use-n
and then add an explicitp
when you want something printed.
-
-
yPhil almost 13 yearsI'll be damned, it works. Thank you very much sir. @sehe Thanks, I will check grep.
-
Jonathan Leffler almost 13 yearsYou 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 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 almost 13 years@Jonathan @przemoc And what would one do to get the opposite ? That is returning the string without the matched bit ?
-
przemoc almost 13 years@xaccrocheur Remove
!
in my boilerplate (and possiblys///
command too; depends on whether you want to further modify it or not). For-n
way it would be/patt/!p
. -
Jonathan Leffler almost 13 years@xaccrocheur:
sed -ne 's/^\(.*\)\(.\)[0-9][0-9]\1\(.*\)$/\1\2\2\3/p'
- untested -
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 over 2 years-ne ... /p is really convenient