dividir el archivo en archivos más pequeños utilizando por número de campos

Me está costando mucho dividir un archivo csv grande (50 GB) en una parte más pequeña. Cada línea tiene unos pocos miles de campos. Algunos de los campos son cadenas entre comillas dobles, otros son enteros, decimales y booleanos.

Quiero analizar el archivo línea por línea y dividir por el número de campos en cada fila. Las cadenas pueden contener varias comas (como por ejemplo), así como varios campos vacíos.

,, 1,30,50, “Vendido por padre, hijo e hija por $ 4,000”, ,,,, 12 ,,, 20.9,0,

Traté de usar

perl -pe' s{("[^"]+")}{($x=$1)=~tr/,/|/;$x}ge ' file >> file2 

para cambiar las comas dentro de las comillas a | pero eso no funcionó. Planeo usar

 awk -F"|" conditional statement appending to new k_fld_files file2 

¿Hay una manera más fácil de hacer esto por favor? Estoy buscando en Python, pero probablemente necesito una utilidad que transmita el proceso del archivo, línea por línea.

Uso de Python: si solo desea analizar CSV, incluyendo delimitadores incrustados, y transmitir con un nuevo delimitador, algo como:

 import csv import sys with open('filename.csv') as fin: csvout = csv.writer(sys.stdout, delimiter='|') for row in csv.reader(fin): csvout.writerow(row) 

De lo contrario, no es mucho más difícil hacer que esto haga todo tipo de cosas.

Ejemplo de salida a archivos por columna (no probado):

 cols_to_output = {} for row in csv.reader(fin): for colno, col in enumerate(row): output_to = cols_to_output.setdefault(colno, open('column_output.{}'.format(colno), 'wb') csv.writer(output_to).writerow(row) for fileno in cols_to_output.itervalues(): fileno.close() 

Aquí hay una alternativa awk .

Suponiendo que las cadenas citadas están bien formateadas, es decir, siempre tienen comillas de inicio y finalización, y no hay comillas dentro de otras comillas, puede hacer el reemplazo que sugirió haciendo un gsub en cada campo que reemplace , con | .

Con pipas

A continuación, se muestra un ejemplo de cómo podría ir esto al agarrar las columnas 3 a 6, 11 y 14-15 con cut coreutils :

 awk -F'"' -v OFS='' ' NF > 1 { for(i=2; i<=NF; i+=2) { gsub(",", "|", $i); $i = FS $i FS; # reinsert the quotes } print }'\ | cut -d , -f 3-6,11,14-15 \ | awk -F'"' -v OFS='' -e ' NF > 1 { for(i=2; i<=NF; i+=2) { gsub("\\|", ",", $i) $i = FS $i FS; # reinsert the quotes } print }' 

Tenga en cuenta que hay un paso de procesamiento posterior adicional que revierte el | a,.

Enteramente en awk

Alternativamente, podría hacer todo el asunto en awk con alguna pérdida de generalidad con respecto a la especificación de rango. Aquí solo tomamos las columnas 3 a 6:

extraer.awk

 BEGIN { OFS = "" start = 3 end = 6 } { for(i=2; i<=NF; i+=2) { gsub(",", "|", $i) $i = FS $i FS } split($0, record, ",") for(i=start; i<=end-1; i++) { gsub("\\|", ",", record[i]) printf("%s,", record[i]) } gsub("\\|", ",", record[end]) printf("%s\n", record[end]) }