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?

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

  • 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. – don_crissti Sep 28 '16 at 10:11
  • @don_crissti that is an excellent solution, you should add it as answer... – Sundeep Sep 28 '16 at 10:15
  • don_crissti's solution worked perfectly thanks for the answer. – aze Sep 28 '16 at 13:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.