18
$ perl --version
This is perl, v5.10.1 (*) built for x86_64-linux-gnu-thread-multi

$ echo -e "foo\nbar" > baz.txt
$ perl -p -e 's/foo\nbar/FOO\nBAR/m' baz.txt
foo
bar

How can I get this replacement to work?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Gabe Kopley
  • 16,281
  • 5
  • 47
  • 60

2 Answers2

40

You can use the -0 switch to change the input separator:

perl -0777pe 's/foo\nbar/FOO\nBAR/' baz.txt

-0777 sets the separator to undef, -0 alone sets it to \0 which might work for text files not containing the null byte.

Note that /m is needless as the regex does not contain ^ nor $.

choroba
  • 231,213
  • 25
  • 204
  • 289
  • 1
    Much better than mine. I'm not used to `-0` switch but in this case suits perfectly. **+1** for that. – Birei May 24 '13 at 19:55
  • 1
    `-0` sets `$/` to `"\000"` and `-0777` to `undef`, but both do file slurp. :o – mpapec May 24 '13 at 20:10
  • 2
    @Сухой27, no. `-0` only slurps the file if it doesn't contain NUL characters. Text files normally don't contain those characters. So for text files it will generally not make a difference, but if you want to slurp the file in regardless of what it may contain, that's `-0777` you want. `-0` is more for processing the output of `find -print0` or `grep -lZ` (NUL delimited records). Compare `printf 'a\0b\0' | perl -l -0 -ne 'print $.'` with `printf 'a\0b\0' | perl -l -0777 -ne 'print $.'` – Stephane Chazelas Aug 19 '16 at 10:24
  • 1
    You'd use `-0`/`-z`/`--null` with GNU `grep` or GNU `sed` because you don't have any other choice there. They don't have a slurp mode, but you can emulate it with `-z` as long as you can guarantee the input doesn't contain NUL characters. (you can still use `pcregrep -M ...` or `gsed ':1;$!{N;b1}...` though) – Stephane Chazelas Aug 19 '16 at 10:34
  • 3
    Another difference between `-0` and `-0777` is that for an empty `baz.txt`, You get 0 records with the former and 1 empty record for the latter (doesn't make a difference here for `s/foo\nbar/FOO\nBAR/` but would for instance for `s/^/prefix/`). – Stephane Chazelas Aug 19 '16 at 10:39
5

It has to do with the -p switch. It reads input one line at a time. So you cannot run a regexp against a newline between two lines because it will never match. One thing you can do is to read all input modifying variable $/ and apply the regexp to it. One way:

perl -e 'undef $/; $s = <>; $s =~ s/foo\nbar/FOO\nBAR/; print $s' baz.txt

It yields:

FOO
BAR
Birei
  • 35,723
  • 2
  • 77
  • 82