Cómo formatear un bucle bash usando sed, awk, grep y wc

Cómo formatear un bucle bash usando sed, awk, grep y wc

Entonces tengo un archivo de texto del que necesito extraer líneas específicas y contar la cantidad de veces que aparece un número en una columna específica. Tengo alrededor de 100 de estos archivos. Puedo hacerlo en pequeños pasos pero quiero hacerlo usando bash/ksh:

foreach i *h3
sed '4p;55p;77q;d' $i >> output.txt
end 

^^^^esto simplemente extraerá las líneas que necesito de cada archivo h3

awk '{print $6}' output.txt | grep 'P2' | wc -l

^^^esto simplemente extraerá la columna 6 de output.txt y contará el número de veces que P2 aparece en la columna 6

¿Hay alguna manera de combinar todo esto en un script bash/ksh?

Respuesta1

Si entendí correctamente:

  • ¿Quiere contar cuántas veces hay "P2" en cualquier lugar dentro del sexto campo de las líneas 4,55 y 77 de algunos archivos (llamados *h3)?

Podrías hacer esto con 1 awk:

awk '
( FNR==4 || FNR==55 || FNR==77 ) {
    if ( $6 ~ "P2" ) { occurence++ } 
}
END {
    printf "There was: %d P2 ", occurence
    printf " among the 6th field on lines 4,55 or 77 of the *h3 files\n"
}' *h3

Nota: cambie $6 ~ "P2"a $6 == "P2"si desea una coincidencia exacta (en lugar de grep, como usó en su propio ejemplo, para que también coincida: somethingP2otherthingy sus variantes)

FNR = Número de registros del archivo = número de líneas en el archivo actual (es decir, comienza nuevamente en 1 en la primera línea de cada archivo) (Archivo actual cuyo nombre también puede conocerse mediante la variable interna: FILENAME)

(NR = aquí no funcionaría, ya que es el número (total) de registros leídos desde el principio (no desde el comienzo del archivo actual))

Respuesta2

Seguro. Aquí hay una manera

p2_count=0
for f in *h3; do
    for ((n=1; n<=77; n++)); do
        IFS= read -r line
        if [[ $n == 4|55|77 ]]; then
            echo "$line"
            set -f
            set -- $line
            set +f
            if [[ $6 == *P2* ]]; then
                ((p2_count++))
            fi
        fi
    done < "$f"
done > output.txt
echo "saw P2 in 6th column $p2_count times"

Respuesta3

O usando unintentoun trazador de líneas:

for i in *h3; do sed '4p;55p;77q;d' $i | awk '{print $6}' | grep 'P2'; done | wc -l

O más corto usando grep -c:

for i in *h3; do sed '4p;55p;77q;d' $i | awk '{print $6}'; done | grep -c 'P2'

Respuesta4

Por lo general, cuando una pregunta es "¿cómo proceso un montón de archivos de texto usandoherramienta(s) específica(s)¿en un bucle bash?", la respuesta es, en parte, "No use un bucle bash, use (algunas o todas) las herramientas mismas". A veces, parte de la respuesta es incluso "No use esas herramientas, usa esto en su lugar".

Lo que quieras se puede hacer awksolo, sin necesidad de un bucle de shell. O sedo grepo wc:

awk 'BEGIN {OFS="\t"}
     FNR ~ /^(4|10|17)$/ && $6 ~ /P2/ {count++}
     ENDFILE { print FILENAME, count; count=0 }' *h3

Nota:ARCHIVO FINAL es específico de GNU awk. No funcionará con otras versiones de awk.

Y esta versión también imprime un total acumulado para todos los archivos:

awk 'BEGIN {OFS="\t"}
     FNR ~ /^(4|10|17)$/ && $6 ~ /P2/ {count++; total++}
     ENDFILE { print FILENAME, count; count=0 }
     END { print "---", total,"total" }' *h3

El END{}bloque imprime el total y también hace un intento burdo de distinguir el total real de cualquier archivo que tenga el nombre de archivo "total". Lo hace imprimiendo ---en el primer campo, luego el total y luego la cadena totalen el tercer campo. Esto está lejos de ser perfecto, pero en muchos casos es suficiente. Es mejor que wcno intentarlo en absoluto.

información relacionada