Introducción
Estoy tratando de capturar qué proceso(s) comenzó(n) durante un período de tiempo limitado.
Creé un script (ps-suspects.sh
) donde:
- Ejecuto
ps-suspects.sh
desde la terminal. - Inicio y cierro una aplicación, digamos la Calculadora de escritorio.
- Presiono Ctrl +C para finalizar
ps-suspects.sh
- Quiero saber cuál es el nombre del proceso para la Calculadora
- No quiero una lista de todos los demás nombres de procesos que se ejecutan durante todo el período de la instantánea.
El problema
Tengo un fragmento de código que necesita ajustes:
$ sort -k15 ~/pid.log | uniq -f14 -c
Esto es lo que produce:
$ head ~/pid.tmp
1 /mnt/e/bin/ps-suspects.sh Possible suspects causing problems
63 1 S root 127 2 0 60 -20 - 0 - Sep08 ? 00:00:00 [acpi_thermal_pm]
63 1 S root 75 2 0 60 -20 - 0 - Sep08 ? 00:00:00 [ata_sff]
63 1 S root 447 2 0 60 -20 - 0 - Sep08 ? 00:00:00 [ath10k_aux_wq]
63 1 S root 446 2 0 60 -20 - 0 - Sep08 ? 00:00:00 [ath10k_wq]
63 1 S avahi 922 910 0 80 0 - 11195 - Sep08 ? 00:00:00 avahi-daemon: chroot helper
63 4 S avahi 910 1 0 80 0 - 11228 - Sep08 ? 00:00:00 avahi-daemon: running [alien.local]
126 0 S rick 2902 2867 0 80 0 - 7409 wait_w Sep08 pts/18 00:00:00 bash
63 0 S rick 25894 5775 0 80 0 - 4908 wait 10:43 pts/2 00:00:00 /bin/bash /mnt/e/bin/ps-suspects.sh
63 0 S root 980 976 0 80 0 - 4921 - Sep08 ? 00:00:01 /bin/bash /usr/local/bin/display-auto-brightness
Quiero eliminar todas las líneas que se producen 63
o más veces.
Resultado deseado
$ ps-suspects.sh
20 times / second ps -elf is captured to /home/rick/pid.log
Type Ctrl+C when done capturing
~/pid.log is sorted and uniq counted on column 15
which is full path and program name.
Then all matches with same unique count (the headings)
are stripped and only new processes started are printed.
This function can help you trace down what processes are
causing you grief for lid close events, hot plugging, etc.
^C
wc of ~/pid.log : 17288 343162 2717102 /home/rick/pid.log
HighCnt: 63
1 /mnt/e/bin/ps-suspects.sh Possible suspects causing problems
26 0 R rick 25976 2051 0 80 0 - 120676 - 10:43 ? 00:00:00 gnome-calculator
62 0 S root 22561 980 0 80 0 - 3589 - 10:42 ? 00:00:00 sleep 60
Pregunta
En este ejemplo 63
aparecerá en el 90%-99% de las líneas en la columna 1 y esas líneas deben eliminarse. Todas las apariciones de 126
también se podría quitar. Entonces cualquier cosa la más ocurrida y más grande se puede eliminar.
¿Puede alguien pensar en el awk
faltante? y/o uniq
y/o grep
para terminar la tarea?
Respuesta aceptada:
Python al rescate:
python3 -c 'import sys,collections;l=[(int(L.split(None,1)[0]),L)for L in sys.stdin.readlines()];m=collections.Counter(x[0]for x in l).most_common(1)[0][0];print(*[x[1]for x in l if x[0]<m],sep="",end="")'
Versión alternativa sin comprimir para usar como archivo de script:
#!/usr/bin/env python3
import sys
import collections
# read lines from stdin (with trailing \n) and extract the number in their first column
items = [(int(line.split(None, 1)[0]), line) for line in sys.stdin]
# find the most common number from the first column
most_common = collections.Counter(item[0] for item in items).most_common()[0][0]
# print input lines in order, but only those with their number lower than the most common
print(*[item[1] for item in items if item[0] < most_common], sep="", end="")
La única suposición que hace este script sobre su entrada, que se espera que se canalice a stdin, es que cada línea tiene un número entero válido en su primera columna separada por espacios en blanco. No es necesario ordenar las líneas de ninguna forma.
Relacionado:¿Qué algoritmo hash se usa para las contraseñas almacenadas en la sombra en 11.10?
most_common = sorted(collections.Counter(item[0] for item in items).most_common(),
key=lambda x:x[::-1])[-1][0]
Ejemplo de entrada:
1 foo
3 bar
2 baz
3 apple
3 banana
2 cherry
4 beep
Salida de ejemplo:
1 foo
2 baz
2 cherry