10

i have a file which contains several instances of \n.

i would like to replace them with actual newlines, but sed doesn't recognize the \n.

i tried

sed -r -e 's/\n/\n/'
sed -r -e 's/\\n/\n/'
sed -r -e 's/[\n]/\n/'

and many other ways of escaping it.

is sed able to recognize a literal \n? if so, how?

is there another program that can read the file interpreting the \n's as real newlines?

sam h
  • 113
  • 1
  • 5
  • If Ashish's suggestion doesnt work then there are some good pointers here: http://stackoverflow.com/questions/1251999/sed-how-can-i-replace-a-newline-n – James Sefton Nov 04 '13 at 05:58

5 Answers5

10

Can you please try this

sed -i 's/\\n/\n/g' input_filename
Ashish
  • 1,856
  • 18
  • 30
  • 1
    Then proably we can `cat input_filename | sed -i 's/\\n/\n/g' >> output_filename` Probably because input file will remain unchanged and desired output will be in different file – Ashish Nov 04 '13 at 06:02
  • Or use `-i.bak` to backup old file with `.bak` extension – mvp Nov 04 '13 at 06:03
  • perfect thanks, i'm already piping it so don't have to worry about editing in place. what does the g flag do? – sam h Nov 04 '13 at 06:07
  • I am glad if it worked for you. Please accept the answer (Click the checkmark next to answer) if it helped your requirement – Ashish Nov 04 '13 at 06:10
  • @brianmarx /g is global (replace all occurrences) – beroe Nov 04 '13 at 06:29
  • /g will do replacements – Ashish Nov 04 '13 at 07:00
1

What exactly works depends on your sed implementation. This is poorly specified in POSIX so you see all kinds of behaviors.

The -r option is also not part of the POSIX standard; but your script doesn't use any of the -r features, so let's just take it out. (For what it's worth, it changes the regex dialect supported in the match expression from POSIX "basic" to "extended" regular expressions; some sed variants have an -E option which does the same thing. In brief, things like capturing parentheses and repeating braces are "extended" features.)

On BSD platforms (including MacOS), you will generally want to backslash the literal newline, like this:

sed 's/\\n/\
/g' file

On some other systems, like Linux (also depending on the precise sed version installed -- some distros use GNU sed, others favor something more traditional, still others let you choose) you might be able to use a literal \n in the replacement string to represent an actual newline character; but again, this is nonstandard and thus not portable.

If you need a properly portable solution, probably go with Awk or (gasp) Perl.

perl -pe 's/\\n/\n/g' file

In case you don't have access to the manuals, the /g flag says to replace every occurrence on a line; the default behavior of the s/// command is to only replace the first match on every line.

tripleee
  • 175,061
  • 34
  • 275
  • 318
0
$ echo "\n" | sed -e 's/[\\][n]/hello/'
laalto
  • 150,114
  • 66
  • 286
  • 303
Bryan Newman
  • 621
  • 3
  • 9
0

awk seems to handle this fine:

echo "test \n more data" | awk '{sub(/\\n/,"**")}1'
test ** more data

Here you need to escape the \ using \\

Jotne
  • 40,548
  • 12
  • 51
  • 55
  • The question was how to replace with a literal newline; though the change is simple (just replace `**` with `\n`). – tripleee Aug 29 '21 at 07:07
0
  1. sed works one line at a time, so no \n on 1 line only (it's removed by sed at read time into buffer). You should use N, n or H,h to fill the buffer with more than one line, and then \n appears inside. Be careful, ^ and $ are no more end of line but end of string/buffer because of the \n inside.
  2. \n is recognized in the search pattern, not in the replace pattern. Two ways for using it (sample):
    sed s/\(\n\)bla/\1blabla\1/
    sed s/\nbla/\
    blabla\
    /
    
    The first uses a \n already inside as back reference (shorter code in replace pattern); the second use a real newline.

So basically

sed "N
$ s/\(\n\)/\1/g
"

works (but is a bit useless). I imagine that s/\(\n\)\n/\1/g is more like what you want.

tripleee
  • 175,061
  • 34
  • 275
  • 318
NeronLeVelu
  • 9,908
  • 1
  • 23
  • 43