21

Greetings, how do I perform the following in BSD sed?

sed 's/ /\n/g'

From the man-page it states that \n will be treated literally within a replacement string, how do I avoid this behavior? Is there an alternate?

I'm using Mac OS Snow Leopard, I may install fink to get GNU sed.

Brett Ryan
  • 26,937
  • 30
  • 128
  • 163
  • 1
    Small correction: `\n` isn't treated literally as such, it gets translated to literal `n` (i.e., the `\` is dropped; but that obviously still isn't the desired outcome). – mklement0 Jul 04 '14 at 19:08

4 Answers4

23

In a shell, you can do:

    sed 's/ /\
/g'

hitting the enter key after the backslash to insert a newline.

Wooble
  • 87,717
  • 12
  • 108
  • 131
  • 1
    Fantastic, thanks Wooble. Is there any known reason why BSD sed doesn't support \n in the replacement string? Just curious. – Brett Ryan Sep 14 '09 at 13:21
  • I'm not sure, but it seems they just decided to not support escapes at all in the replacement string. sed 'y/ /\n/' seems to work, although it only does string replacement; if you need to replace the ' ' with a regex it will fail. Also, the \n seems to be special-cased; \r with get you an 'r', not a carriage return. – Wooble Sep 14 '09 at 13:29
10

Another way:

sed -e 's/ /\'$'\n/g'

See here.

sikmir
  • 178
  • 2
  • 6
  • 3
    +1, but note that this relies on a shell feature, [ANSI C quoting](http://www.gnu.org/software/bash/manual/bash.html#ANSI_002dC-Quoting) (`$'...'`), and some shells do not support it (e.g., `dash` - it's not part of POSIX). Also,`'s/ /\'$'\n''/g'` - wedging a `$'\n'` between two single-quoted strings - is conceptually clearer and more robust. Alternatively, use `$'s/ /\\\n/g'` (note the need to escape the `\ `). – mklement0 Jul 04 '14 at 18:55
7

For ease of use, i personally often use

cr="\n" 
# or (depending version and OS)
cr="
"

sed "s/ /\\${cr}/g"

so it stays on 1 line.

mklement0
  • 382,024
  • 64
  • 607
  • 775
NeronLeVelu
  • 9,908
  • 1
  • 23
  • 43
  • 2
    Interesting; can I suggest calling the variable `nl` rather than `cr`? Assuming you use a shell that supports [ANSI C quoting](http://www.gnu.org/software/bash/manual/bash.html#ANSI_002dC-Quoting) (e.g., `bash`, `ksh`, `zsh`), you could simplify the assignment to `cr=$'\n'`; then you wouldn't have to worry about platform differences. – mklement0 Jul 04 '14 at 19:02
  • cool advice, sur about the `$'\n'` on any "unix" ? it will indeed help (my Sun give me some issue on assignation/action like that with `\n`) – NeronLeVelu Jul 16 '14 at 10:37
  • 1
    `$'\n'` (ANSI-C quoting) should work if you have the right _shell_ (`bash`, `ksh`, or `zsh` - NOT in POSIX-features-only shells such as `dash`, however), so the platform should not matter. (`bash` introduced the feature in version 2.0 (a loooong time ago) - not sure about `ksh`, and `zsh`, but I would expect current systems to have recent-enough versions). – mklement0 Jul 16 '14 at 13:14
  • In NetBSD 9.3, this gives me the error `unterminated substitute in regular expression` :-( I genuinely cannot find a way to make `sed` use newlines in NetBSD, but you could use `awk -v RS=" " "{print}"` instead, taken from [this answer](https://askubuntu.com/a/461148) – FWDekker Feb 19 '23 at 09:26
0

To expand on @sikmir's answer: In Bash, which is the default shell on Mac OS X, all you need to do is place a $ character in front of the quoted string containing the escape sequence that you want to get interpreted. Bash will automatically translate it for you.

For example, I removed all MS-DOS carriage returns from all the source files in lib/ and include/ by writing:

grep -lr $'\r' lib include | xargs sed -i -e $'s/\r//'
find . -name '*-e' -delete

BSD grep would have interpreted '\r' correctly on its own, but using $'\r' doesn't hurt.

BSD sed would have misinterpreted 's/\r//' on its own, but by using $'s/\r//', I avoided that trap.

Notice that we can put $ in front of the entire string, and it will take care of all the escape sequences in the whole string.

$ echo $'hello\b\\world'
hell\world
Quuxplusone
  • 23,928
  • 8
  • 94
  • 159