Newlines in sed on Mac OS X

You can brew install gnu-sed and replace calls to sed with gsed.


To use it as sed instead of gsed, brew helpfully prints the following instructions after you install:

GNU "sed" has been installed as "gsed".
If you need to use it as "sed", you can add a "gnubin" directory
to your PATH from your bashrc like:

    PATH="/usr/local/opt/gnu-sed/libexec/gnubin:$PATH"

That is, append the following line to your ~/.bashrc or ~/.zshrc:

export PATH="/usr/local/opt/gnu-sed/libexec/gnubin:$PATH"

These would also work:

echo 'foo bar' | sed 's/ /\
/g'

echo 'foo bar' | sed $'s/ /\\\n/g'

lf=$'\n'; echo 'foo bar' | sed "s/ /\\$lf/g"

OS X's sed doesn't interpret \n in the replace pattern, but you can use a literal linefeed preceded by a line continuation character. The shell replaces $'\n' with a literal linefeed before the sed command is run.


The workaround you found passes a single argument string to sed -e.

That argument ends up being a string in the familiar sed s/ / /g format.

That string is created in two parts, one after the other.

The first part is quoted in '...' form.

The second part is quoted in $'...' form.

The 's/ /\' part gets the single-quotes stripped off, but otherwise passes through to sed just as it looks on the command-line. That is, the backslash isn't eaten by bash, it's passed to sed.

The $'\n/g' part gets the dollar sign and the single-quotes stripped off, and the \n gets converted to a newline character.

All together, the argument becomes

s/ /\newline/g

[That was fun. Took a while to unwrap that. +1 for an interesting question.]


The expression $'...' is a bash-ism which produces ... with the standard escape sequences expanded. Th \' before it just means a backslash followed by the end of the quoted section, the resulting string is s/ /\. (Yes, you can switch quoting in the middle of a string; it doesn't end the string.)

POSIX standard sed only accepts \n as part of a search pattern. OS X uses the FreeBSD sed, which is strictly POSIX compliant; GNU, as usual, adds extra stuff and then Linux users all think that is some kind of "standard" (maybe I'd be more impressed if either of them had a standards process).


There's a very easy to visually see what's happening. Simply echo the string!

echo 's/$/\'$'\n/g'

results in

s/$/\
/g

which is equivalent to s/$/\newline/g

If you didn't have the extra \ before the newline, the shell would interpret the newline as the end of the command prematurely.