1

Using sed with this regular expression:

message=$(echo "$path" | sed -E 's/(.+pattern[0-9][0-9]*).+/\1/')

With this expression, lines like this:

/lol/pattern03657/qsd/qsd/pattern0001/qsd/

will be replaced by:

/lol/pattern03657/qsd/qsd/pattern0001

whereas I would like them to be:

/lol/pattern03657/

I thought sed would replace only the first occurrence but it doesn't seem to do so. What do I have to change to make my code behave this way?

1 Answer 1

3

That is because *, + are greedy quantifiers, will try to match as much as possible

$ echo '/lol/pattern03657/qsd/qsd/pattern0001/qsd/' | sed -E 's/(.+pattern[0-9][0-9]*).+/\1/'
/lol/pattern03657/qsd/qsd/pattern0001

perl has a non-greedy quantifier by adding ? to +

$ echo '/lol/pattern03657/qsd/qsd/pattern0001/qsd/' | perl -pe 's/(.+?pattern\d+\/).+/\1/'
/lol/pattern03657/

or use grep with pcre option if available

$ echo '/lol/pattern03657/qsd/qsd/pattern0001/qsd/' | grep -oP '^.+?pattern\d+/'
/lol/pattern03657/


One workaround with sed is if you know where your string occurs. For ex:

$ echo '/lol/pattern03657/qsd/qsd/pattern0001/qsd/' | sed -E 's|^(/[^/]+/pattern[0-9][0-9]*/).+|\1|'
/lol/pattern03657/

Here, from start of line, one set of /text/ precedes the string

3
  • 1
    ... and because regex is greedy you can simply do sed -E 's|(pattern[0-9][0-9]*/).*|\1|' which will match from the 1st (leftmost) to the end of line and replace with just the 1st occurrence. Sep 28, 2016 at 10:11
  • @don_crissti that is an excellent solution, you should add it as answer...
    – Sundeep
    Sep 28, 2016 at 10:15
  • don_crissti's solution worked perfectly thanks for the answer.
    – aze
    Sep 28, 2016 at 13:10

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .