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!

foonbar

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!

link|improve this question
this would probably work too: echo "foo bar" | tr ' ' '\n' – glenn jackman Jul 6 '11 at 18:17
1  
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 Z. Xiao Jul 6 '11 at 22:50
feedback

3 Answers

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

link|improve this answer
Now I understand the $'...' part. But... what is s/ /\ ? What do you mean by switch quoting? – Ivan Z. Xiao Jul 6 '11 at 22:53
1  
'...' 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 '11 at 23:01
feedback

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

link|improve this answer
feedback

These would also work:

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

The point is that you need to add a line continuation character (\) before a newline in sed, and \n is only unescaped when using ANSI-C quotes.

link|improve this answer
feedback

Your Answer

 
or
required, but never shown

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