345

I have a file of strings that are comma separated. I'm trying to replace the commas with a new line. I've tried:

sed 's/,/\n/g' file

but it is not working. What am I missing?

codeforester
  • 39,467
  • 16
  • 112
  • 140
WildBill
  • 9,143
  • 15
  • 63
  • 87

14 Answers14

414

Use tr instead:

tr , '\n' < file
Prince John Wesley
  • 62,492
  • 12
  • 87
  • 94
  • 1
    It is not wokring in bash shell $ tr , '\n' aitr usage: tr [-Ccsu] string1 string2 tr [-Ccu] -d string1 tr [-Ccu] -s string1 tr [-Ccu] -ds string1 string2 – Learner Jan 20 '16 at 18:41
  • 6
    Replacing a comma with a semicolon also works: `tr ',' ';' < input.csv > output.csv` – Wim Deblauwe Feb 24 '16 at 09:29
347

Use an ANSI-C quoted string $'string'

You need a backslash-escaped literal newline to get to sed. In bash at least, $'' strings will replace \n with a real newline, but then you have to double the backslash that sed will see to escape the newline, e.g.

echo "a,b" | sed -e $'s/,/\\\n/g'

Note this will not work on all shells, but will work on the most common ones.

miken32
  • 42,008
  • 16
  • 111
  • 154
Walter Mundt
  • 24,753
  • 5
  • 53
  • 61
134
sed 's/,/\
/g'

works on Mac OS X.

Max Nanasy
  • 5,871
  • 7
  • 33
  • 38
  • 3
    Thanks for this - Wondered why my old linux trick didn't work in OSX. But this does! – Wyatt Ward May 10 '14 at 18:18
  • 7
    This is the only solution that works in a sed script. – Firstrock May 12 '14 at 19:12
  • 6
    Note that the backslash *escapes* the literal newline (so that it's not a command terminator): it is *not* a line continuation character (as in bash, etc.). To see the difference, try to write the above command without the quotes: the backslash will instead be interpreted by the shell as a line continuation character and it and the newline will be discarded. Conversely, include the contents of the quoted expression (without quotes) in a separate comma-to-newline.sed file (which eliminates shell syntax), and it works! – Nils von Barth Oct 11 '14 at 04:06
  • 2
    this is good since it can replace anything, not a character. tr seems work with only characters. if you put a string as first parameter, it will replace all the occurrence of the characters, not the string. – Shawn Mar 09 '15 at 20:03
  • I'm on Yosemite, and I couldn't get this to work until I switched the escaped literal newline with *two* backslashes, not one. – yurisich Aug 05 '15 at 20:27
  • 1
    @Droogans Are you using bash, sh, or a different shell? Are you sure you're using single quotes instead of double quotes? – Max Nanasy Aug 10 '15 at 07:09
  • I can confirm it doesn't work on Yosemite. I'm using single quotes, and it doesn't work for me on OSX 10.10.5. No matter how many backslashes I use, I get the error: invalid command code \ – 7stud Jan 14 '17 at 09:51
  • This gave me a clue. I did this in the end: `sed $'s/,/\\\n/'` to keep everything on one line – Wivlaro Feb 14 '17 at 12:50
26

If your sed usage tends to be entirely substitution expressions (as mine tends to be), you can also use perl -pe instead

$ echo 'foo,bar,baz' | perl -pe 's/,/,\n/g'
foo,
bar,
baz
nar8789
  • 727
  • 6
  • 9
18

MacOS is different, there is two way to solve this problem with sed in mac

  • first ,use \'$'\n'' replace \n, it can work in MacOS:

    sed 's/,/\'$'\n''/g' file
    
  • the second, just use an empty line:

    sed 's/,/\
    /g' file
    
  • Ps. Pay attention the range separated by '

  • the third, use gnu-sed replace the mac-sed

Felix
  • 495
  • 4
  • 9
17

Apparently \r is the key!

$ sed 's/, /\r/g' file3.txt > file4.txt

Transformed this:

ABFS, AIRM, AMED, BOSC, CALI, ECPG, FRGI, GERN, GTIV, HSON, IQNT, JRCC, LTRE,
MACK, MIDD, NKTR, NPSP, PME, PTIX, REFR, RSOL, UBNT, UPI, YONG, ZEUS

To this:

ABFS
AIRM
AMED
BOSC
CALI
ECPG
FRGI
GERN
GTIV
HSON
IQNT
JRCC
LTRE
MACK
MIDD
NKTR
NPSP
PME
PTIX
REFR
RSOL
UBNT
UPI
YONG
ZEUS
Chris Seymour
  • 83,387
  • 30
  • 160
  • 202
15

This works on MacOS Mountain Lion (10.8), Solaris 10 (SunOS 5.10) and RHE Linux (Red Hat Enterprise Linux Server release 5.3, Tikanga)...

$ sed 's/{pattern}/\^J/g' foo.txt > foo2.txt

... where the ^J is done by doing ctrl+v+j. Do mind the \ before the ^J.

PS, I know the sed in RHEL is GNU, the MacOS sed is FreeBSD based, and although I'm not sure about the Solaris sed, I believe this will work pretty much with any sed. YMMV tho'...

Joel Purra
  • 24,294
  • 8
  • 60
  • 60
Ramon Rey
  • 171
  • 1
  • 3
7

To make it complete, this also works:

echo "a,b" | sed "s/,/\\$(echo -e '\n\r')/"
ryenus
  • 15,711
  • 5
  • 56
  • 63
  • 1
    This would also be fitting for the Obfuscated C contest, except it's Bash ;) – Aaron R. Mar 17 '14 at 20:31
  • @AaronR. I agree :-). Surely I prefer the `tr` solution, which is already the accepted answer. – ryenus Mar 24 '14 at 07:49
  • 1
    This worked on OS X. Why is it `\n\r` instead of `\r\n`? I tried `\r\n` which is the necessary order on Windows. However, after I do this it's leaving a lot of `^M` carriage return characters in `vim`, so I think it's supposed to be only `\n` but `\n` alone doesn't work. – NobleUplift Mar 24 '17 at 18:09
4

Though I am late to this post, just updating my findings. This answer is only for Mac OS X.

$ sed 's/new/
> /g' m1.json > m2.json
sed: 1: "s/new/
/g": unescaped newline inside substitute pattern

In the above command I tried with Shift+Enter to add new line which didn't work. So this time I tried with "escaping" the "unescaped newline" as told by the error.

$ sed 's/new/\
> /g' m1.json > m2.json 

Worked! (in Mac OS X 10.9.3)

Nils von Barth
  • 3,239
  • 2
  • 26
  • 27
user2300875
  • 529
  • 1
  • 6
  • 20
3
$ echo $PATH | sed -e $'s/:/\\\n/g' 
/usr/local/sbin
/Library/Oracle/instantclient_11_2/sdk
/usr/local/bin

...

Works for me on Mojave

2

Just to clearify: man-page of sed on OSX (10.8; Darwin Kernel Version 12.4.0) says:

[...]

Sed Regular Expressions

 The regular expressions used in sed, by default, are basic regular expressions (BREs, see re_format(7) for more information), but extended
 (modern) regular expressions can be used instead if the -E flag is given.  In addition, sed has the following two additions to regular
 expressions:

 1.   In a context address, any character other than a backslash (``\'') or newline character may be used to delimit the regular expression.
      Also, putting a backslash character before the delimiting character causes the character to be treated literally.  For example, in the
      context address \xabc\xdefx, the RE delimiter is an ``x'' and the second ``x'' stands for itself, so that the regular expression is
      ``abcxdef''.

 2.   The escape sequence \n matches a newline character embedded in the pattern space.  You cannot, however, use a literal newline charac-
      ter in an address or in the substitute command.

[...]

so I guess one have to use tr - as mentioned above - or the nifty

sed "s/,/^M
/g"

note: you have to type <ctrl>-v,<return> to get '^M' in vi editor

t3az0r
  • 449
  • 4
  • 8
2

The sed on macOS Mojave was released in 2005, so one solution is to install the gnu-sed,

brew install gnu-sed

then use gsed will do as you wish,

gsed 's/,/\n/g' file

If you prefer sed, just sudo sh -c 'echo /usr/local/opt/gnu-sed/libexec/gnubin > /etc/paths.d/brew', which is suggested by brew info gnu-sed. Restart your term, then your sed in command line is gsed.

DawnSong
  • 4,752
  • 2
  • 38
  • 38
0

FWIW, the following line works in windows and replaces semicolons in my path variables with a newline. I'm using the tools installed under my git bin directory.

echo %path% | sed -e $'s/;/\\n/g' | less
Jeff LaFay
  • 12,882
  • 13
  • 71
  • 101
-1

I have found another command that is working also.

find your_filename.txt -type f -exec sed -i 's/,/\n/g' {} \;
shawon
  • 984
  • 7
  • 15