awk cómo separar en diferentes archivos todas las líneas con el mismo contenido en una columna determinada

awk cómo separar en diferentes archivos todas las líneas con el mismo contenido en una columna determinada

Tengo un archivo csv grande (Test.csv), que se parece a esto:

1,2,3,A,5
1,2,3,B,5
1,2,3,E,5
1,2,3,D,5
1,2,3,Z,5
1,2,3,B,5

Quiero imprimir las líneas en las que la cuarta columna tiene el mismo contenido en diferentes archivos. En realidad, necesito unir estas líneas que tienen el mismo contenido en un nuevo archivo csv o txt, denominado contenido de la cuarta columna. Por ejemplo:

Producción:

Presentar un

1,2,3,A,5
1,2,3,A,5
1,2,3,A,5

Archivo B

1,2,3,B,5
1,2,3,B,5

Dado que el archivo de entrada es grande, no tengo idea de cuántos patrones diferentes hay en esta cuarta columna. La columna 4 contiene solo palabras y las otras columnas contienen palabras y/o números.

Como no tengo experiencia, investigué preguntas similares e incluso probé el siguiente código:

awk 'NR==FNR{a[$4]=NR; next} $NF in a {print > "outfile" a[$NF]}' Test.csv

pero nada funcionó. ¿Alguien puede ayudarme, por favor? Gracias de antemano.

Respuesta1

Esto funcionará de manera eficiente usando la clasificación POSIX y cualquier awk en cualquier shell en cada cuadro UNIX:

$ sort -t, -k4,4 test.csv |
    awk -F, '$4!=prev{close(out); out="File"$4; prev=$4} {print > out}'

$ head -n 20 File*
==> FileA <==
1,2,3,A,5

==> FileB <==
1,2,3,B,5
1,2,3,B,5

==> FileD <==
1,2,3,D,5

==> FileE <==
1,2,3,E,5

==> FileZ <==
1,2,3,Z,5

Algunas cosas a tener en cuenta:

  1. algunos awks necesitan poner pares alrededor de una expresión en el lado derecho de la redirección de salida, y
  2. algunos awks fallan si no cierra los archivos de salida a medida que avanzan y, por lo tanto, intenta retener demasiados archivos abiertos una vez que superan una docena de archivos de salida, y
  3. mantener varios archivos de salida abiertos es muy ineficiente en todos los awks que lo permiten, y
  4. cerrar los archivos de salida línea por línea para tener en cuenta eso será muy ineficiente en todos los awks.

Respuesta2

Debería poder utilizar simplemente el campo en el nombre del archivo de salida. Una solución sencilla:

awk -F, '{print > ("file_" $4 ".csv")}' Test.csv

Esto funciona al menos en GNU awk y crea archivos file_A.csv, file_B.csvetc. Tenga en cuenta que esto mantiene abiertos todos los archivos de salida y se vuelve más lento cuanto más hay, especialmente si alcanza el límite de archivos abiertos por proceso.

-F,establece el separador de campo en la coma.

No estoy seguro de qué debería hacer el guión que mostraste.

Respuesta3

Algo como esto:

$ awk -F, '{ print $0 >> "file-" $4 ".txt"; }' ./tmp.txt

Tal como lo menciona la respuesta de @ilkkachu, la bandera -Fes cambiar el separador de campo de los espacios en blanco predeterminados a una coma. Debe utilizar >>en lugar de  > para no sobrescribir el archivo si existe.

Respuesta4

Pitón

#!/usr/bin/python
uni=[]
k=open('file.txt','r')
for i in k:
    
    g=i.split(",")[3].strip()
    if g not in uni:
        uni.append(g)



for m in uni:
    f=open("{0}.txt".format(m),'w')
    l=open('file.txt','r')
    for d in l:
        if m in d.split(",")[3].strip():
            f.write(d)

Ya se proporciona la mejor solución en awk, es solo mi intento.

for i in `awk -F "," '{if(!seen[$4]++)print $4}' file.txt`; do awk -v i="$i" -F "," '$4==i{print $0}' file.txt >$i.txt; done

información relacionada