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.