Uma nota de portabilidade. O formato de saída para ps -A
é não especificado por POSIX para sistemas não compatíveis com Unix ( como o FreeBSD) (você notará que as seções do formato de saída e a descrição da opção -f
estão todas marcadas com XSI na especificação), então você não pode realmente pós-processá-lo de forma confiável .
Por exemplo, com o ps
de procps
no Linux, ele produzirá, PID TTY TIME CMD
colunas (onde CMD
é o nome do processo, não o comando args) enquanto no FreeBSD ele gera PID TT STAT TIME COMMAND
(com COMMAND
sendo os argumentos).
Dado seu uso de grep -v grep
, eu suponho que você esteja esperando o último ou pelo menos que ps -A
produza os argumentos do comando que o processo executou em oposição a apenas o nome do processo (geralmente derivado do nome do arquivo do último comando execute ou o primeiro argumento (0 th )).
Se o seu grep
se destina a grep
apenas nos argumentos do comando, você deve usar:
ps -A -o pid= -o args=
cuja saída é especificada por POSIX.
Agora, seu problema é que mykill
está se matando porque o mykill foo
corresponde a foo
.
Outro problema é que mykill grep
não mataria nada.
Aqui, você poderia fazer:
#! /bin/sh -
PATTERN=${1?} export PATTERN
trap '' TERM # ignore SIGTERM for the shell and its children
ps -A -o pid= -o args= | awk '$0 ~ ENVIRON["PATTERN"] {
system("kill " $1); exit}'
(note que POSIX não especifica o caminho do utilitário POSIX sh
nem o mecanismo she-bang, portanto /bin/sh
pode não ser um shell POSIX. Na prática, o she-bang é suportado na maioria dos POSIX sistemas e /bin/sh
é um POSIX sh
ou o Bourne sh
e o código acima deve funcionar em ambos).
Embora isso não seja o ideal, pois sempre retorna um status de saída true (0) mesmo quando nenhum processo é encontrado. Uma abordagem melhor seria:
#! /bin/sh -
pattern=${1?}
trap '' TERM # ignore SIGTERM for the shell and its children
ps -A -o pid= -o args= | grep -e "$pattern" | {
read pid args && kill "$pid"
}
Em ambos os casos, eliminamos apenas o primeiro processo de correspondência, como a abordagem grep -m 1
sugere que você queira fazer.
Agora, com trap '' SIGTERM
, garantimos que nossos processos não sejam eliminados, o que seria OK se matássemos all os processos correspondentes, mas, como aqui, estamos apenas matando o primeiro correspondente , o problema é que aquele primeiro pode muito bem ser aquele executando mykill pattern
ou grep pattern
.
Em vez de adicionar alguns grep -ve grep -e mykill
(o que não seria infalível, pois poderia excluir mais processos do que o pretendido), você poderia comparar os IDs do processo dos processos correspondentes.
#! /bin/sh -
pattern=${1?}
trap '' TERM # ignore SIGTERM for the shell and its children
# just in case
psoutput=$(exec ps -A -o pid= -o ppid= -o args=)
printf '%s\n' "$psoutput" | grep -e "$pattern" | {
while read -r pid ppid args; do
if [ "$pid" -ne "$$" ] && [ "$ppid" -ne "$$" ]; then
kill "$pid"
exit # with the exit status of kill above
fi
done
exit 1 # not found
}
(observe que $(...)
e read -r
são POSIX, mas não Bourne).
Ou usando ksh93
, bash
, zsh
ou yash
(nenhum dos quais são comandos POSIX), que é um shell com correspondência de expressão regular interna:
#! /bin/bash -
pattern=${1?}
trap '' TERM # ignore SIGTERM for the shell and its children
# just in case
psoutput=$(exec ps -A -o pid= -o ppid= -o args=)
printf '%s\n' "$psoutput" | {
while read -r pid ppid args; do
if ((pid != $$ && ppid != $$)) && [[ $args =~ $pattern ]]; then
kill "$pid"
exit # with the exit status of kill above
fi
done
exit 1 # not found
}