Imprimir una nueva línea usando awk

Imprimir una nueva línea usando awk

Tengo una gran cantidad de archivos en los que necesito eliminar filas específicas y luego colocar los datos que saqué en una hoja de cálculo. Un ejemplo sería mi archivo muestra:

Name: w

Age: x

Height: y

Weight: z

Solo quiero la edad, la altura y el peso, así que primero ejecuté:

grep -E 'Age|Height|Weight' [input file] > output.txt

Debido a la cantidad de archivos, mi salida ahora se ve así

Age 1
 
Height 1

Weight 1

Age 2

Height 2

Weight 2

etc...

Lo que ahora quiero es ejecutar un script awk para que revise mi nuevo archivo output.txt y primero encuentre cada fila con la palabra 'Edad' y la imprima. Una vez que ha hecho todos los de 'Edad', hace la altura y luego el peso. Ejecuté el script:

awk -F"\t" '/Age/ {print} /Height/ {print}' output.txt >output2.txt

Pero si solo lo imprime como el archivo original. ¿Cómo lo cambio para que después de haber hecho todos los de Edad, encuentre los de altura?

EDITAR:

Mi resultado deseado es que el archivo sea

Edad 1

Edad 2

Altura 1

Altura 2

Peso 1

Peso 2

etc..

Solo para aclarar, Edad 1 es la fila con "edad" del archivo 1, etc.

Respuesta1

awk solo ejecuta el archivo una vez de forma predeterminada, ejecutando todos los bloques en orden, razón por la cual le brinda el resultado que obtuvo. Puedes obtener el comportamiento que deseas usandouna matrizpara guardar las líneas a medida que avanza, sin dejar de procesar el archivo solo una vez:

BEGIN {
    AgeIndex = 1
    HeightIndex = 1
}
/Age/ {
    ages[AgeIndex] = $0
    AgeIndex+=1
}
/Height/ {
    heights[HeightIndex] = $0
    HeightIndex+=1
}
END {
    for (x = 1; x < AgeIndex; x++)
        print ages[x] "\n"
    for (x = 1; x < HeightIndex; x++)
        print heights[x] "\n"
}

Guárdelo en, digamos, filter.awky luego ejecute:

awk -f filter.awk output.txt > output2.txt

para obtener el resultado que desea:

$ awk -f filter.awk < data
Age 1

Age 2

Height 1

Height 2

Lo que estamos haciendo es crear dos matrices agesy heightsguardar cada línea coincidente en ellas a medida que avanzamos. AgeIndexmantiene hasta qué punto estamos en la matriz. Al final, imprimimos cada línea que guardamos (y una nueva línea adicional como la que desee), primero todas las edades, luego todas las alturas.

Las matrices mantendrán el archivo completo en la memoria al final, por lo que si su archivo es particularmente grande, tendrá que compensar el uso de memoria por el tiempo para revisar el archivo completo más de una vez. En este punto, es esencialmente lo mismo que un programa en cualquier otro idioma: si no tiene ningún motivo particular para usar awk, es posible que prefiera otro idioma. Para ser honesto, creo que lo recomendaría: awk no te ofrece mucho aquí.

Respuesta2

Con gawk:

$ awk -F"\t" '
    { a[$1]++ }
    END {
        n = asorti(a,b);
        for (i = 1; i <= n; i++) {
            print b[i];
            if (i%2 == 0) {
                printf "\n";
            }
        }
    }
' output.txt
Age 1
Age 2

Height 1
Height 2

Weight 1
Weight 2

Respuesta3

Supongo que las líneas en blanco no son parte de su archivo real, o que al menos no le importan. Si es así, todo lo que necesitas es sort:

$ cat output.txt
Age 1
Height 1
Weight 1
Age 2
Height 2
Weight 2

$ sort output.txt
Age 1
Age 2
Height 1
Height 2
Weight 1
Weight 2

Sin embargo, a menos que sus archivos sean demasiado grandes para guardarlos en la memoria, podría ser más sencillo hacer todo en un solo paso:

grep -whE 'Age|Height|Weight' *txt | sort > outfile

Lo anterior buscará Ageo Heighto Weighten todos los archivos cuyo nombre termine txten el directorio actual ( *txt). Significa -w"coincidir solo con palabras completas" (para que Ageno coincidan, Ageingpor ejemplo), es -hnecesario porque sin él, el nombre del archivo se imprime junto con la línea coincidente cuando se proporciona más de un archivo de entrada. Permite -Eexpresiones regulares extendidas que nos dan |OR.

NOTA: Si, por alguna razón, realmente desea una línea en blanco adicional entre cada entrada (que no es lo que grepproduciría su comando), puede agregarla con:

grep -whE 'Age|Height|Weight' *txt | sort | sed 's/$/\n/'

Ejemplo

$ for i in {1..3}; do echo -e "Name $i\nAge $i\nHeight $i\nWeight $i" > $i.txt; done
$ for f in *txt; do echo " -- $f --"; cat $f; done
 -- 1.txt --
Name 1
Age 1
Height 1
Weight 1
 -- 2.txt --
Name 2
Age 2
Height 2
Weight 2
 -- 3.txt --
Name 3
Age 3
Height 3
Weight 3

$ grep -whE 'Age|Height|Weight' *txt | sort
Age 1
Age 2
Age 3
Height 1
Height 2
Height 3
Weight 1
Weight 2
Weight 3

En cualquier caso, incluso si sortno es suficiente para usted, haría este tipo de cosas en Perl, no awk(esto supone que desea líneas en blanco adicionales que, nuevamente, probablemente no desee):

$ perl -ane '$k{$F[0]}.=$_."\n" if /./; 
    END{print $k{$_},"\n" for sort keys (%k)}' output.txt 
Age 1

Age 2


Height 1

Height 2


Weight 1

Weight 2


 

Puedes pasar eso head -n -2para deshacerte de las dos últimas líneas en blanco si no las quieres.

Respuesta4

pythonsolución para este problema:

from collections import defaultdict
f = open("output.txt", "r")
d = defaultdict(list)
for line in f:
   line = line.strip()
   if line != '':
     arr = line.split(" ")
     d[arr[0]].append(arr[1])
print d.items()

Hice un hash usando la primera columna y la puse en una lista.

información relacionada