I find that \n doesn't work in sed under Mac OS X. Specifically, say I want to break the words separated by a single space into lines:

# input
foo bar

I use,

echo "foo bar" | sed 's/ /\n/'

But the result is stupid, the \n is not escaped!


After I consulted to google, I found a workaround:

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

After reading the article, I still cannot understand what \'$'\n/g' means. Can some one explain it to me, or if there is any other way to do it? Thanks!

  • 1
    this would probably work too: echo "foo bar" | tr ' ' '\n' Jul 6, 2011 at 18:17
  • 3
    Thanks for the advice. But currently I just use the above case as an example, I do need to know how to escape a \n.
    – Ivan Xiao
    Jul 6, 2011 at 22:50
  • Possible duplicate: stackoverflow.com/questions/21621722/…
    – hyiltiz
    Apr 19, 2017 at 7:05
  • Maybe you could also use Perl instead of sed which would make it simpler. See my answer here for details. Basically, it would be echo "foo bar" | perl -pe 's/ /\n/ or perl -pe 's/ +/\n/g to replace all spaces or groups of spaces by a new line.
    – mivk
    Sep 7, 2020 at 12:26
  • I just noticed a script running on Big Sur escaped the newline just fine, but the same script on Catalina showed your output... not a newline. I think Apple updated it to address this issue. Dec 23, 2020 at 5:21

7 Answers 7


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:


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

export PATH="/usr/local/opt/gnu-sed/libexec/gnubin:$PATH"
  • Using the same software on all platform is way easier (at last to me) than dealing with every specificities of the Mac version. Beware, the option is now --with-default-names and not --default-names. However, this option did not worked on my installation, so I had to put a alias gsed=sed in my ~/.profile to make it work.
    – Clément
    May 11, 2015 at 11:40
  • 4
    This is an ugly workaround. It doesn't explain why sed on OS X behaves the way it does and makes the incorrect assumption that gnu-sed is more correct. Don't be a GNU-addict and stick to POSIX standards to avoid problems in the long run. Oct 8, 2015 at 2:13
  • It is how Apple should make its OS works by default. Why use the name of a program and then make it works differently? I waste an hour because of this...
    – rascio
    Apr 4, 2017 at 10:58
  • @rascio - because OS X is BSD-like and Linux is Linux-like.
    – iAdjunct
    May 30, 2018 at 14:30
  • @rascio I think you'll find that GNU sed is the newcomer; BSD sed dates back to 1979 (see en.wikipedia.org/wiki/Version_7_Unix). Sep 10, 2018 at 5:19

These would also work:

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

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.

  • 6
    Why does sed $'s/ /\\\n/g' work, but not sed $'s/\\\n/ /g'? Jan 3, 2016 at 23:03
  • 2
    @alec You can't use sed even in linux/unix to remove newlines because its parsed/split at each newline. If you run this in linux/unix, it won't do anything either: echo -e 'foo\nbar' | sed 's/\n//'
    – wisbucky
    Oct 27, 2017 at 1:05

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).

  • Now I understand the $'...' part. But... what is s/ /\ ? What do you mean by switch quoting?
    – Ivan Xiao
    Jul 6, 2011 at 22:53
  • 2
    '...' is one kind of shell quoting; $'...' is another. There's also "..." and \x to quote a single character. You can combine those in a single word, which is what was being done there, switching from a normal '' string to a $'' string to translate the \n. As for the rest, it's building up a sed command (s/text/replacement/flags). In this case the command is started, including a backslash at the end to protect the literal newline that the $'\n/g' appends. The result is to replace all (the /g flag) spaces with newlines.
    – geekosaur
    Jul 6, 2011 at 23:01

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

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

results in


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.

  • this should have been the accepted answer
    – grepit
    Aug 27, 2021 at 21:26

This workaround works on Mac and the script can be executed also on Linux

if [[ $uname -eq "Darwin" ]]; then

echo 'foo bar' | sed -e "s| |${NL}|" 

A bit more compact form of @max-zerbini's answer:

[[ $(uname) -eq "Darwin" ]] && NL=$'\\\n' || NL="\n"
echo 'foo bar' | sed -e "s| |${NL}|" 

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.