28

I am happy that grep does support Perl Compatible Regular Expressions with the -P option.

Is there a reason why the tool sed does not have this feature?

galoget
  • 2,943
  • 2
  • 20
  • 24
guettli
  • 2,932
  • 12
  • 67
  • 115
  • 7
    It's [Perl Compatible Regular Expressions](https://en.wikipedia.org/wiki/Perl_Compatible_Regular_Expressions) though... ;-) – Byte Commander Jun 29 '18 at 11:39
  • 2
    [Same question from 2012 on the Mailing List](https://lists.gnu.org/archive/html/bug-gnu-utils/2012-11/msg00001.html) – pLumo Jun 29 '18 at 11:41

4 Answers4

27

Work-around:

You can use the Pathological Eclectic Rubbish Lister:

perl -pe 's/../../g' file

or inline replace:

perl -i -pe 's/../../g' file

This works for the cases where I use sed. If things get more complicated I write a small python script.

BTW, I switched to No Shell-Scripting

mivk
  • 5,082
  • 1
  • 47
  • 56
guettli
  • 2,932
  • 12
  • 67
  • 115
  • Well that's great for substitution, but how would you do other sed stuff in Perl? like for example `/delete this line/ d` – wjandrea Nov 26 '18 at 15:34
  • 1
    The most promising thing I found after a quick search is [`s2p`](http://manpages.ubuntu.com/manpages/trusty/man1/perlutil.1.html) (sed to Perl), though I just tried it and the output was VERY verbose. – wjandrea Nov 26 '18 at 16:00
  • 1
    @wjandrea I updated the answer: "This works for the cases where I use `sed`. If things get more complicated I write a small python script." – guettli Nov 27 '18 at 08:06
  • 2
    @wjandrea: `perl -ne 'print unless /delete this line/'` – Adrian Pronk Mar 18 '20 at 01:05
  • 1
    FWIW, `perl -pie 's/...' somefile` fails with `Can't open perl script "s/...": No such file or directory`, while `perl -pi -e 's/...' somefile` works fine (perl v5.28.1 on Debian 10). This is probably because `-i` takes an (optional) backup suffix, so it eats the `e` option. – Jakob Sep 22 '21 at 06:53
9

In the case of GNU Sed, the stated reason appears to be

I was afraid it fell into one of those 'cracks'...though from what was said at the time, some part of the work was already done and it looked like a matter of docs and packaging... (though, I admit, in Computer Sci, the last 10% of the work often takes 90% of the time...

See GNU bug report logs - #22801 status on committed change: upgrading 'sed' RE's to include perlRE syntax - or search the sed-devel Archives for "PCRE" if you want more details.

Don't forget you can use perl itself for many of the simple one-liners for which you might want to use PCRE in sed.

steeldriver
  • 131,985
  • 21
  • 239
  • 326
2

As my substitution needs have become more complex, using perl -pe becomes preferable to sed -e. In particular, being able to use perl character classes and the quantifiers is more concise than the hoops I need to jump through for sed.

journalctl -u auditd -S 'yesterday' |\
  perl -pe 's/^(\w{3} \d{2} \d{2}:\d{2}:\d{2}) ([\w-]+) audispd/$1 generic-hostname audispd/;
      s/node=[\w-]+/node=generic-hostname/;'

vs

journalctl -u auditd -S "yesterday" |\
  sed -e 's/^\([[:alpha:]]\{3\} [[:digit:]]\{2\} [[:digit:]]\{2\}:[[:digit:]]\{2\}:[[:digit:]]\{2\}\) \([[:alpha:]-]\+\) audispd/\1 generic-hostname audispd/;
      s/node=\([[:alpha:]-]\+\) /node=generic-hostname /;'

I could use [0-9] instead of [[:digit:]] and [A-Za-z] instead of [[:alpha:]], but a) both of those are longer than the perl equivalents and b) [A-Za-z] will match non-ASCII characters like the perl equivalents can.

bosses-r-dum> echo 'å' | sed -e 's/[A-Za-z]/X/'
å
bosses-r-dum> echo 'å' | perl -CS -pe 's/\w/X/'
X
bosses-r-dum> 

If you have to deal with unicode, being able to add a flag and have things "Just Work" is very handy. I tend to grow my regexp's organically, so using the same tool for 'simple' and 'complex' regexp's makes sense because my 'simple' regexp can easily turn into a 'complex' one if/when requirements change and I don't need to do any tooling changes (change all [x]\{#\} instances into [x]{#} and the like).

1

Personally I found it easier to do in Python than Perl or Sed.

cat file \
| python3 -c 'import sys, re; s = sys.stdin.read(); s=re.sub(r"regex", "replace string", s); print(s);' \
| sudo tee file

full example

# add quay and docker registries to approved cri-o registries
cat /etc/crio/crio.conf \
| python3 -c 'import sys, re; s = sys.stdin.read(); s=re.sub(r"#registries\s+\=\s+\[\n#\s+\]", "registries = [\"docker.io\",\"quay.io\"]", s); print(s);' \
| sudo tee /etc/crio/crio.conf

jmcgrath207
  • 209
  • 2
  • 6
  • 3
    It's a matter of taste and habits I guess, but taking your 3 line example, I prefer the much simpler Perl version: `sudo perl -077 -i.bak -pe 's/#(registries\s*\=)\s*\[\s*#\s*\]/$1 ["docker.io","quay.io"]/;' crio.conf`. (the `-077` makes it read the whole file. `-i.bak` does it in-place with a backup file using a ".bak" extension. And `$1` is the part in parenthesis). And it's about half the characters to type :-) – mivk Oct 19 '21 at 15:07