J'ai un fichier délimité par des tabulations qui a plus de 200 millions de lignes. Quel est le moyen le plus rapide de linux pour convertir cela en un fichier csv? Ce fichier contient plusieurs lignes d'informations d'en-tête que je devrai supprimer, mais le nombre de lignes d'en-tête est connu. J'ai vu des suggestions pour sed
et gawk
, mais je me demande s'il existe un choix "préféré".
Juste pour clarifier, il n'y a pas d'onglets incorporés dans ce fichier.
Si tout ce que vous devez faire est translate tous les caractères de tabulation en caractères de virgule, tr
est probablement le chemin à parcourir.
L'espace vide ici est un onglet littéral:
$ echo "hello world" | tr "\\t" ","
hello,world
Bien entendu, si vous avez incorporé des onglets dans des littéraux de chaîne dans le fichier, ceux-ci seront également traduits incorrectement. mais des onglets littéraux intégrés seraient assez rares.
Si vous craignez les virgules intégrées, vous devrez utiliser une méthode légèrement plus intelligente. Voici un script Python qui extrait les lignes TSV de stdin et écrit les lignes CSV sur 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)
Exécutez-le à partir d'un shell comme suit:
python script.py < input.tsv > output.csv
Perl -lpe 's/"/""/g; s/^|$/"/g; s/\t/","/g' < input.tab > output.csv
Perl est généralement plus rapide dans ce genre de choses que sed, awk et Python.
sed -e 's/"/\\"/g' -e 's/<tab>/","/g' -e 's/^/"/' -e 's/$/"/' infile > outfile
Putain de critiques, tout cite, CSV s'en fiche.
<tab>
est le caractère de tabulation réel.\t n'a pas fonctionné pour moi. En bash, utilisez ^ V pour le saisir.
Si vous souhaitez convertir l'intégralité du fichier tsv en un fichier csv:
$ cat data.tsv | tr "\\t" "," > data.csv
Si vous souhaitez omettre certains champs:
$ cat data.tsv | cut -f1,2,3 | tr "\\t" "," > data.csv
La commande ci-dessus convertira le fichier data.tsv en fichier data.csvcontenant uniquement les trois premiers champs.
La solution python de @ ignacio-vazquez-abrams est excellente! Pour les personnes qui cherchent à analyser les onglets des délimiteurs, la bibliothèque vous permet en fait de définir des délimiteurs arbitraires. Voici ma version modifiée pour gérer les fichiers délimités par des tubes:
import sys
import csv
pipein = csv.reader(sys.stdin, delimiter='|')
commaout = csv.writer(sys.stdout, dialect=csv.Excel)
for row in pipein:
commaout.writerow(row)
en supposant que vous ne voulez pas changer l'en-tête et en supposant que vous n'avez pas d'onglets incorporés
# cat file
header header header
one two three
$ awk 'NR>1{$1=$1}1' OFS="," file
header header header
one,two,three
NR> 1 saute le premier en-tête. vous avez mentionné que vous connaissez le nombre de lignes d'en-tête, utilisez donc le nombre correct pour votre propre cas. avec cela, vous n'avez également pas besoin d'appeler d'autres commandes externes. une seule commande awk fait le travail.
une autre façon si vous avez des colonnes vierges et que vous vous souciez de cela.
awk 'NR>1{gsub("\t",",")}1' file
en utilisant sed
sed '2,$y/\t/,/' file #skip 1 line header and translate (same as tr)
Vous pouvez également utiliser xsv pour cela
xsv input -d '\t' input.tsv > output.csv
Lors de mon test sur un fichier tsv de 300 Mo, il était environ 5 fois plus rapide que la solution python (2,5 vs 14).
l'awel oneliner suivant prend en charge les guillemets + quote-escaping
printf "flop\tflap\"" | awk -F '\t' '{ gsub(/"/,"\"\"\"",$i); for(i = 1; i <= NF; i++) { printf "\"%s\"",$i; if( i < NF ) printf "," }; printf "\n" }'
donne
"flop","flap""""
Je pense qu'il est préférable de ne pas chatter le fichier car cela peut créer un problème dans le cas d'un fichier volumineux. La meilleure façon peut être
$ tr ',' '\t' < csvfile.csv > tabdelimitedFile.txt
La commande obtiendra une entrée de csvfile.csv et stockera le résultat sous forme de tabulation séparée dans tabdelimitedFile.txt.