tags:

views:

604

answers:

5

I have a tab-delimited file that has over 200 million lines. What's the fastest way in linux to convert this to a csv file? This file does have multiple lines of header information which I'll need to strip out down the road, but the number of lines of header is known. I have seen suggestions for sed and gawk, but I wonder if there is a "preferred" choice.

Just to clarify, there are no embedded tabs in this file.

+2  A: 

If all you need to do is translate all tab characters to comma characters, tr is probably the way to go.

The blank space here is a literal tab:

$ echo "hello   world" | tr "\\t" ","
hello,world

Of course, if you have embedded tabs inside string literals in the file, this will incorrectly translate those as well; but embedded literal tabs would be fairly uncommon.

Mark Rushakoff
More common are embedded commas in the source, which then require wrapping with quotes. Which is troublesome if there are embedded quotes...
kibibu
Thanks for the `tr` suggestion. How does it compare to `sed` with speed? Suppose you wanted to skip the header start at line number x and continue to the rest of the file. Is there a way to implement this with `tr`? (I should also clarify that there are no embedded commas in the file.)
andrewj
@andrewj: `tr` should be much faster, as it's just doing character-by-character replacement instead of regex matching. As for skipping header, the easiest thing is to just process in two chunks - if you know the length, `head -n <length> input > output; tail -n +<length+1> input | tr ... >> output`; if you don't know the length, probably something with `grep -n`...
Jefromi
@andrew, sed has support for transliteration, also you can use address range.
ghostdog74
+4  A: 

If you're worried about embedded commas then you'll need to use a slightly more intelligent method. Here's a Python script that takes TSV lines from stdin and writes CSV lines to stdout:

import sys
import csv

tabin = csv.reader(sys.stdin, dialect=csv.excel_tab)
commaout = csv.writer(sys.stdout, dialect=csv.excel)
for row in tabin:
  commaout.writerow(row)

Run it from a shell as follows:

python script.py < input.tsv > output.csv
Ignacio Vazquez-Abrams
Unless you know for sure that there are no embedded commas and no embedded tabs, this is a very reliable way to do it. Even though it probably doesn't meet the criteria for being 'the fastest'.
dave
+1  A: 

assuming you don't want to change header and assuming you don't have embedded tabs

# cat file
header  header  header
one     two     three

$ awk 'NR>1{$1=$1}1' OFS="," file
header  header  header
one,two,three

NR>1 skips the first header. you mentioned you know how many lines of header, so use the correct number for your own case. with this, you also do not need to call any other external commands. just one awk command does the job.

another way if you have blank columns and you care about that.

awk 'NR>1{gsub("\t",",")}1' file

using sed

sed '2,$y/\t/,/' file #skip 1 line header and translate (same as tr)
ghostdog74
A: 
sed -e 's/"/\\"/g' -e 's/<tab>/","/g' -e 's/^/"/' -e 's/$/"/' infile > outfile

Damn the critics, quote everything, CSV doesn't care.

is the actual tab character. \t didn't work for me. In bash, use ^V to enter it.

Will Hartung
+1  A: 
perl -lpe 's/"/""/g; s/^|$/"/g; s/\t/","/g' < input.tab > output.csv

Perl is generally faster at this sort of thing than the sed, awk, and Python.

pabs