awk: Extracción de un número fijo de filas donde el último número de fila puede variar

Esta pregunta puede parecer un duplicado, pero solo a primera vista.
Por supuesto, ya no necesitaría ayuda sobre cómo codificar una línea que extrae un número fijo de líneas continuas (por ejemplo, 5 en este ejemplo) de una fuente de datos, por ejemplo, top :

 $ top -b -n1 | awk 'BEGIN {printf "%23s %7s\n","cpu","mem"} NR==8,NR==12 {printf "%-16s %6s%% %6s%%\n",$12,$9,$10}' 

Esto es incluso una muy útil de una sola línea que mostrará los processs en el sistema que toman la mayoría de la CPU, con el uso de la memory que se imprime en una columna adicional.

Hasta ahora, tan bueno … sin embargo, no es tan trivial. Para get esta list, la top es necesaria y puede (en baja carga del sistema) aparecer como process en esta list. Prefiero no querer eso, ya que estas llamadas se hacen en intervalos y regularmente aparecen en la top (aunque solo sea por un corto time). Se sabe que queremos comenzar en la línea 8 (NR == 8). Sin embargo, ¿qué pasa si un segundo top en otro escritorio virtual fue olvidado en un terminal que también arruina la list? En este caso, se deben omitir dos processs top , por lo que la última línea para procesar será 14.

Entonces, para mejorar esta salida y filtrar cada línea top que está allí, un contador parece obligatorio (¿quizás un bucle for que salgamos con un break ?). Lamentablemente mis bashs con un bucle for e i = <number> han sido infructuosos hasta el momento, porque preferiría imprimir cada línea tantas veces como indique.

He encontrado una solución bastante hackish, que funciona pero puede no ser adecuada para casos más complejos:

 top -b -n1 | grep -v ' \btop\b$' | awk 'BEGIN {printf "%23s %7s\n","cpu","mem"} NR==8,NR==12 {printf "%-16s %6s%% %6s%%\n",$12,$9,$10}' 

(Nota: Esto puede dar resultados no deseados si el nombre de usuario en la segunda columna pasa a ser "superior" también)

De todos modos, ¿podría get una pista de cómo hacer eso en awk por favor (y deshacerse de la grep )?
Gracias por adelantado.

Esto no responde tu pregunta,
pero resuelve el problema que estás tratando de resolver, de una manera completamente diferente:

El command completo es esto (ver a continuación, por ejemplo, salida):

 ps -o comm,%cpu,%mem --sort -%cpu -A | head -6 

Describiré las partes de esto:

  • usando ps para tener más control sobre la salida
  • Imprimiendo solo las tres columnas que necesitamos con -o comm,%cpu,%mem
  • Haga que ps ordere los datos internamente --sort -%cpu , por CPU, inversa.
  • Listar todos los processs con -A
  • Muestra el encabezado y las primeras 5 líneas del resultado por | head -6 | head -6

La salida es similar a la salida de su primer command:

 $ ps -o comm,%cpu,%mem --sort -%cpu -A | head -6 COMMAND %CPU %MEM firefox 8.9 15.5 Xorg 1.3 5.6 parcellite 0.3 1.6 compiz 0.2 1.8 konsole 0.1 0.9 

El process ps aparece en la list completa, se podría excluir en function del PID principal.

Si queremos excluir top processs top otro lugar, podemos hacerlo en function del nombre del command.

El- -A seleccionando todos los processs sería reemplazado por -N ... :

 ps ... -N --ppid $$ -C top 

Como ahora necesitamos excluir processs, utilizamos -N para seleccionar todos los processs que no coinciden.

Para excluir ps , usamos que tiene el shell interactivo actual como process principal, por lo que tendrá el pid principal, PPID del shell. El PID del shell actual es $$ .
Así que --ppid $$ coincide con todos los processs hijos del shell actual, y sabemos que solo habrá uno, ps .

Queremos también excluir los processs top que pueden ejecutarse en otras pantallas en la misma máquina. Hacemos eso al hacer coincidir el nombre del command con -C top .

El command completo con exclusión del process ps sí mismo (y solo esto) y todos top processs top sería:

 ps -o comm,%cpu,%mem --sort -%cpu -N --ppid $$ -C top | head -6 
  command superior |  awk 'BEGIN { imprimir encabezado ;  recuento = 5}
                    NR> = 8 {if ($ 0 ~ / su expresión regular superior /) siguiente;
                            imprimir campos ;  if (--count == 0) exit} ' 

En cada línea que comience con el n. ° 8, si coincide con la top , ignórelo. De lo contrario, imprima la parte que desee. La quinta vez que imprime una línea (que no coincide con la top ), salga.