Matar todos os trabalhos em segundo plano

63

Existe uma forma mais compacta de eliminar trabalhos em segundo plano do que:

for i in {1..5}; do kill %$i; done

Além disso, {1..5} obviamente possui um número mágico codificado, como posso fazer "N" com N sendo o número certo, sem fazer um:

$(jobs | wc -l)

Na verdade, eu uso \ j no PS1 para obter o número de trabalhos gerenciados, isso é equivalente?

Robottinosino
fonte
3
kill $(jobs -p)parece mais fácil.
Jw013 19/07
Eu preferiria matar trabalhos individualmente, se possível. (Talvez eu tenha entendido mal o seu comentário) #
Robottinosino 19/07/12
for pid in $(jobs -p); do kill $pid; done?
jw013
3
@ jw013 Não é apenas mais fácil, é realmente correto (publique como resposta), ao contrário de uma solução baseada na contagem das linhas de saída das jobsquais só funciona se os trabalhos forem numerados consecutivamente. Ah, e “matar tarefas individualmente” não faz sentido: passar vários PIDs para o killcomando faz exatamente a mesma coisa que passá-los separadamente.
Gilles 'SO- stop be evil'
Eu estava digitando o comando incorretamente, mate $ (jobs -p) words e parece muito correto para mim também. Pronto para aceitar.
Robottinosino

Respostas:

101

Para apenas killtodos os trabalhos em segundo plano gerenciados por bash, faça

kill $(jobs -p)

Note-se que uma vez que ambos jobse killsão incorporadas bash, você não deve correr em quaisquer erros da lista de argumentos muito longa tipo.

jw013
fonte
2
Também para a posteridade, o que bahamat acha que é a maneira de fazê-lo zshdesqualifica-os como qualquer autoridade sobre o assunto.
peth
Eu sinto que deveria saber disso, mas como o '$' funciona aqui?
fersarr
11
@fersarr Aqui você vai
jw013
@bahamat Isso realmente não funciona, pois o PID pode estar no campo 2 ou 3, dependendo de o trabalho ser% + ou% - ou não. O que funciona é o kill %${(k)^jobdirs}que é realmente mais longo; se você precisar listar os PIDs, poderá usar ainda mais ${${jobstates#*:*:}%%=*}.
Gilles 'SO- stop be evil'
No CentOS, meu prompt de espera por mais entrada>
Janac Meena
15

Use em xargsvez do $(jobs -p)subcomando, porque se jobs -pestiver vazio, o comando kill falhará.

jobs -p | xargs kill
brunocascio
fonte
11
Porém, isso tem o mesmo efeito exato, imprime a ajuda e sai com o código 123
cat
11
O comando funciona bem no OSX, mas não funciona no Debian
brunocascio
Isso funciona muito bem no CentOS 6
Janac Meena 13/11/19
jobs -p | xargs -rn10 killfará melhor se jobs -pnão retornar PIDs. Observe que a -ropção é extensão GNU.
NarūnasK
Como mencionado acima, -ré o formato abreviado da --no-run-if-emptyextensão GNU, para a xargsqual instrui a não executar o comando se stdin não tiver dados.
Anthony G - justiça para Monica
3

Prefiro verificar se há algum trabalho antes de matá-lo - dessa forma, o script não falhará se não houver nada em execução.

Também é mais curto para digitar. Jogue isso no seu .bash_profile:

function killjobs () {
    JOBS="$(jobs -p)";
    if [ -n "${JOBS}" ]; then;
        kill -KILL ${JOBS};
    fi
}

Então corra:

killjobs

Para matar todos os trabalhos em execução.

mikemaccana
fonte
1

Tenho vários comandos compostos em segundo plano que desejo finalizar normalmente, enviando SIGINT para cada processo, no macOS. Nenhuma das outras soluções funcionou corretamente para isso, então eu vim com isso:

jobs -p | xargs -n1 pkill -SIGINT -g

jobs -p lista os processos em segundo plano iniciados pelo shell atual.

xargs -n1 executa o pkill uma vez para cada trabalho.

pkill -SIGINT -g envia SIGINT (o mesmo que ctrl + c) para todos os processos no grupo de processos.

Clement Cherlin
fonte
1

Acho que dependendo da saída jobs -p, a solução pode ser um pouco diferente. No meu caso

$ jobs -p
[1]  - 96029 running    some job
[2]  + 96111 running    some other job

Portanto, não é bom fazer o seguinte.

$ jobs -p | xargs kill
kill: illegal process id: [1]

Por outro lado, a execução kill $(jobs -p)funciona, mas envolve muitas mensagens de erro, pois as cadeias não PID também são passadas kill.

Portanto, minha solução é grepo PID primeiro e, em seguida xargs, use o seguinte:

$ jobs -p | grep -o -E '\s\d+\s' | xargs kill
Fanchen Bao
fonte
11
Qual shell você está usando? O que echo $0mostra? O que help jobsmostra? A saída ilustrada não é compatível com POSIX ; qualquer implementação de jobsdeve ter uma -popção com o comportamento pretendido.
Wildcard
11
Obrigado por apontar isso. Estou usando o zsh, e essa é a razão da saída estranha. Eu mudei para o bash e jobs -psó produzi PID. Acabei de aprender que o zsh não é totalmente compatível com POSIX.
Fanchen Bao 06/07
0

Parece que jobs -p | xargs killfaz o trabalho, no entanto, produz alguma saída indesejada, canalizada para matar. Aqui estou agrupando a saída de jobs -pter / não ter o caractere + ou -

function killjobs() {
    JOBS=$(jobs -p)
    echo $JOBS | grep -v "+\|-"| awk '{print $2}' | xargs kill -9
    echo $JOBS | grep "+\|-"| awk '{print $3}' | xargs kill -9
}

E depois você pode simplesmente ligar killjobs

samvel1024
fonte