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: somethingP2otherthing
y 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 awk
solo, sin necesidad de un bucle de shell. O sed
o grep
o 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 total
en el tercer campo. Esto está lejos de ser perfecto, pero en muchos casos es suficiente. Es mejor que wc
no intentarlo en absoluto.