Regex is not working properly with sed but works in regex101

Viewed 152

I am just trying to strip everything before the first occurance of a single space character from each line. Eg.50G This is a Test (0000) 1234p (String).ext should become This is a Test (0000) 1234p (String).ext

So i am using this simple regex - ^.+?\s(.*) whereby i am just trying to wrap everything after the first space character in a group and then trying to substitute the whole match with the 1st group

Now this problem is that its working well in regex101 - https://regex101.com/r/1dAUcO/1 but when i try the same regex in terminal with sed , it returns a different output . Here's the sed command - echo "50G This is a Test (0000) 1234p (String).ext" | sed -E 's|^.+?\s(.*)|\1|g'

3 Answers

You are using this sed:

sed -E 's|^.+?\s(.*)|\1|g

Where your intention of .+? is to make it a lazy match however sed (even in ERE mode) doesn't support lazy quantifier.

If you consider perl then it would work as is since perl has support for lazy quantifier:

echo "50G This is a Test (0000) 1234p (String).ext" |
perl -pe 's|^.+?\s(.*)|\1|g'

This is a Test (0000) 1234p (String).ext

However I would strongly recommend using cut for this as you don't have to bother about using a regex and this is what cut is made for:

echo "50G This is a Test (0000) 1234p (String).ext" |
cut -d " " -f2-

This is a Test (0000) 1234p (String).ext

sed regex flavor is POSIX that does not support lazy/non-greedy quantifiers.

You can use

sed -E 's|^[^[:space:]]+[[:space:]]*||'

With GNU sed,

sed -E 's|^\S+\s*||'

See an online demo:

#!/bin/bash
s="50G This is a Test (0000) 1234p (String).ext"
sed -E 's|^[^[:space:]]+[[:space:]]*||g' <<< "$s"
## => This is a Test (0000) 1234p (String).ext
sed -E 's|^\S+\s*||' <<< "$s"
## => This is a Test (0000) 1234p (String).ext

You surely can use lazy quantifiers with perl:

perl -pe 's/^.+?\s//'

Note you do not need to capture the rest of the string to put it back with a backreference.

With awk code, you could try following too.

awk '
{
  val=""
  for(i=1;i<=NF;i++){
    if($i~/\([^)]*\)/){
      val=(val?val OFS:"")$(i-1) OFS $(i)
    }
  }
  print val
}
'  Input_file

Explanation: Adding detailed explanation for above.

awk '                     ##Starting awk program from here.
{
  val=""                  ##Nullifying val here.
  for(i=1;i<=NF;i++){     ##Traversing through all fields of current line here.
    if($i~/\([^)]*\)/){   ##Checking if current field is like (...) then do following.
      val=(val?val OFS:"")$(i-1) OFS $(i)  ##Creating val which has current and previous field value in it, keep appending its value to it.
    }
  }
  print val               ##Printing val here.
}
'  Input_file             ##mentioning Input_file name here.
Related