Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

regexp (sed) suppress "no match" output

Tags:

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..?

like image 295
yPhil Avatar asked May 15 '11 22:05

yPhil


People also ask

How do you make sed not greedy?

sed does not support "non greedy" operator. You have to use "[]" operator to exclude "/" from match. P.S. there is no need to backslash "/".

What is\ 1 in sed?

The "\1" is the first remembered pattern, and the "\2" is the second remembered pattern. Sed has up to nine remembered patterns. This will output "abcd" and delete the numbers. This, when used as a filter, will print lines with duplicated words.

Can SED fail?

If the sed command fails, for example, if you try to run it on a file you don't have write access to or one that doesn't exist, sed will exit with a non-0 exit status. The exit status just indicates whether sed managed to do what you told it to do, and echo "foo. bar" | sed 's/pop.


2 Answers

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.

like image 53
przemoc Avatar answered Sep 30 '22 19:09

przemoc


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.

like image 44
sehe Avatar answered Sep 30 '22 21:09

sehe