103

I have the following data in multiple lines:

foo
bar
qux
zuu
sdf
sdfasdf

What I want to do is to convert them to one comma separated line:

foo,bar,qux,zuu,sdf,sdfasdf

What's the best unix one-liner to do that?

Benjamin W.
  • 46,058
  • 19
  • 106
  • 116
neversaint
  • 60,904
  • 137
  • 310
  • 477
  • If the solutions below do not produce the required results, e.g. only the last line's content showing, you may have unwanted control characters in your input, e.g. `\r`. You can check that by piping the input to `hd` or `hexdump`. `\r` will (in conjunction with `\n`) produce the two-byte sequences `0a0d`. Fix with `|sed 's/\r//g'`. – valid Oct 20 '14 at 15:57
  • This question is a duplicate, but not all of the answers are. – reinierpost Oct 30 '14 at 10:41

8 Answers8

178

Using paste command:

paste -d, -s file
Guru
  • 16,456
  • 2
  • 33
  • 46
  • 11
    But how to accomplish that for a variable or a pipe? Update myself: Using -s without value .... | paste -d, -s – NeoMorfeo Oct 28 '15 at 14:37
  • 2
    While this works for when one wants to convert newlines (`\n`) into commas, it seems that one cannot use this method if one needs to convert newlines into "`, `" which is required for many other commands. – CoderGuy123 Jul 27 '16 at 03:48
  • 7
    @NeoMorfeo You can use a `-` to read from pipe as well. Ex: `echo -e "1\n2\n3" | paste -d, -s -` – Carson Anderson Feb 06 '17 at 23:58
92

file

aaa
bbb
ccc
ddd

xargs

cat file | xargs

result

aaa bbb ccc ddd 

xargs improoved

cat file | xargs | sed -e 's/ /,/g'

result

aaa,bbb,ccc,ddd 
Serhii Kuzmychov
  • 1,186
  • 8
  • 10
  • 1
    xargs turns multi-line into one line space-separated, then sed replaces all space by ','(or ' ,' if you will use sed -e 's/ /\ ,/g' ( by the way -e can be omited) – Serhii Kuzmychov Aug 24 '13 at 14:11
  • usually xargs is not intended for t but it works :) – Serhii Kuzmychov Aug 24 '13 at 14:17
  • and it more prefer way for every day use insted of the one bellow – Serhii Kuzmychov Aug 24 '13 at 14:19
  • Thanks for the step by step! I had a file with one entry per line, (fn, ln,id,status, blank line.) I needed it in CSV, so I swapped "blank line" with an unused symbol (sed -e 's/^$/#/') before using the mod you've explained. – Bee Kay Oct 31 '16 at 19:34
  • I found this to be the solution I was looking for, not the accepted one because it works for pipes and multiple files and you can pass it to tr -s " " "\t" if you want to add tabs and so forth. Thank you. – jimh Sep 05 '17 at 00:45
12

There are many ways it can be achieved. The tool you use mostly depends on your own preference or experience.

Using tr command:

tr '\n' ',' < somefile

Using awk:

awk -F'\n' '{if(NR == 1) {printf $0} else {printf ","$0}}' somefile
Chris Seymour
  • 83,387
  • 30
  • 160
  • 202
n3rV3
  • 1,096
  • 8
  • 10
10

xargs -a your_file | sed 's/ /,/g'

This is a shorter way.

chrlaura
  • 1,307
  • 1
  • 9
  • 11
Serhii Kuzmychov
  • 1,186
  • 8
  • 10
8

based on your input example, this awk line works. (without trailing comma)

awk -vRS="" -vOFS=',' '$1=$1' file

test:

kent$  echo "foo
bar
qux
zuu
sdf
sdfasdf"|awk -vRS="" -vOFS=',' '$1=$1' 
foo,bar,qux,zuu,sdf,sdfasdf
Kent
  • 189,393
  • 32
  • 233
  • 301
  • You only need to use `-v` if you want the variables available in the BEGIN block, slightly more concise `awk '$1=$1' RS= OFS=, file`. – Chris Seymour Apr 02 '13 at 12:31
  • 3
    For clarity and to avoid getting surprised when you later do try to use a variable in a BEGIN block, I'd always use -v unless setting a variable to different values between files. FYI omitting the space between -v and the variable name makes your script un-necessarily gawk-specific so I'd use `-v RS=` instead of `-vRS=`. – Ed Morton Apr 02 '13 at 14:13
  • @EdMorton thx for the comment. (the "space" between -v and va). I learned many tips from you :). Personally I always use `-v` too. – Kent Apr 02 '13 at 14:22
6

Perl one-liner:

perl -pe'chomp, s/$/,/ unless eof' file

or, if you want to be more cryptic:

perl '-peeof||chomp&&s/$/,/' file
choroba
  • 231,213
  • 25
  • 204
  • 289
2
sed -n 's/.*/&,/;H;$x;$s/,\n/,/g;$s/\n\(.*\)/\1/;$s/\(.*\),/\1/;$p'
protist
  • 1,172
  • 7
  • 9
1
perl -pi.bak -e 'unless(eof){s/\n/,/g}' your_file

This will create a backup of original file with an extension of .bak and then modifies the original file

Vijay
  • 65,327
  • 90
  • 227
  • 319