
Estou tentando criar um script para encontrar o número PID apenas com o nome do processo e o número legal, mas não estou conseguindo.
Responder1
Usando pgrep
para primeiro obter os PIDs de todos os processos que correspondem à expressão dada como o primeiro argumento e, em seguida, fazer um loop por eles para extrair aqueles que possuem um bom valor correspondente ao segundo argumento.
find_pid_by_name_and_nice () {
pgrep -- "${1:?missing process name}" |
xargs -I {} ps -o pid= -o nice= -p {} |
awk -v nice="${2?missing nice value}" '$NF == nice { print $1 }'
}
Teste:
$ find_pid_by_name_and_nice
find_pid_by_name_and_nice:1: 1: missing process name
find_pid_by_name_and_nice:3: 2: missing nice value
$ find_pid_by_name_and_nice netdata
find_pid_by_name_and_nice:3: 2: missing nice value
$ find_pid_by_name_and_nice netdata 19
258881
258937
$ find_pid_by_name_and_nice netdata 15
(sem saída)
Responder2
by_name_and_nice(){ grep -hoPs "^[^ ]+(?= \($1\)( [^ )]+){16} $2 )" /proc/*/stat; }
by_name_and_nice bash 0
encontrará todos bash
os processos com gentileza = 0 (o padrão),
by_name_and_nice 'b.*' '.*'
encontrará todos os processos com seus nomes começando com b
, não importando sua gentileza, e assim por diante.
Se você também obtém processos com novas linhas e lixo binário em seus nomes, pode precisar de algo um pouco mais complicado:
by_name_and_nice(){
local -; set -o pipefail
LC_ALL=C grep -zhoPs "^[^ ]+(?= \($1\)( [^ )]+){16} $2 )" /proc/*/stat | xargs -0rn1
}
Para corresponder a uma nova linha no nome do processo, você deve usar by_name_and_nice '(?s:foo.*)' 0
(leia sobre osintaxe regex pcreusado pela opção do GNU grep -P
).
Isto é apenas para fins de demonstração; é bastante inútil tentar selecionar por um valor agradável sem algum operador maior ou menor que. Além disso, a seleção pelo nome do processo não é muito confiável, porque o nome do processo está sob o controle total do processo, que é cruelmente abusado por qualquer malware e crapware de dois bits para se autodenominar ps
ou bash
. Uma ideia melhor seria selecionar pelo nome base do binário, como em
find /proc/*/exe -lname '*/whatever'
Desenvolvendo tudo o que resta como exercício para o leitor ;-)
Responder3
POSIXly, com ps
e awk
:
by_name_and_nice() {
# returns pids of processes with $2 as niceness and whose
# process name matches the $1 extended regexp
ps -A -o pid= -o nice= -o comm= |
NAME=$1 NICE=$2 awk '
$2 == ENVIRON["NICE"] {
pid = $1
sub(/^[[:space:]]*[^[:space:]]+ +[^[:space:]]+ /, "")
if ($0 ~ ENVIRON["NAME"]) print pid
}'
}
Isso pressupõe que haja um único caractere de espaço entre a coluna de gentileza e o nome do processo. Esse é o caso da implementação procps-ng normalmente encontrada em sistemas baseados em Linux, mas não é garantida pelo POSIX. Você pode remover todos os caracteres de espaço em branco após a coluna de gentileza, mas isso corre o risco de deturpar processos cujo nome começa com espaço em branco.
Observe que o procps-ng ps
pelo menos altera caracteres não imprimíveis ?
na saída e o que constitui um caractere não imprimível depende da localidade do chamador de ps
. Por exemplo, um processo com UTF-8 Stéphane
como nome poderia ser renderizado como St??phane
se a localidade usasse um conjunto de caracteres diferente de UTF-8.
As procps-ng
implementações de ps
does suportam uma -C
opção para combinar processos por nome (inspirado em HP/UX' ps
), embora seja uma correspondência exata de igualdade byte a byte em vez de uma correspondência de expressão regular, então você poderia fazer:
by_name_and_nice() {
# returns pids of processes with $2 as niceness and whose
# process name is exactly $1
ps -C "$1" -o pid= -o nice= |
awk -v nice="$2" '$2 == nice {print $1}'
}