ti-enxame.com

Como posso executar um comando que sobreviverá ao fechamento do terminal?

Às vezes, quero iniciar um processo e esquecê-lo. Se eu iniciá-lo na linha de comando, assim:

redshift

Não consigo fechar o terminal ou isso acabará com o processo. Posso executar um comando para fechar o terminal sem interromper o processo?

339
Matthew

Um dos 2 a seguir deve funcionar:

$ Nohup redshift &

ou

$ redshift &
$ disown

Veja o seguinte para obter mais informações sobre como isso funciona:

342
Steven D

Se o seu programa estiver já em execução, você poderá pausá-lo com Ctrl-Z, puxe-o para segundo plano com bg e depois disown, desta forma:

$ sleep 1000
^Z
[1]+  Stopped                 sleep 1000
$ bg
$ disown
$ exit
147
Stefan

Boa resposta já foi publicada por @StevenD, mas acho que isso pode esclarecer um pouco mais.

O motivo pelo qual o processo é interrompido na finalização do terminal é que o processo iniciado é um processo filho do terminal. Depois de fechar o terminal, isso também matará esses processos filhos. Você pode ver a árvore de processos com pstree, por exemplo, ao executar kate & no Konsole:

init-+
     ├─konsole─┬─bash─┬─kate───2*[{kate}]
     │         │      └─pstree
     │         └─2*[{konsole}]

Para tornar o processo kate desanexado de konsole quando você terminar konsole, use Nohup com o comando, desta forma:

Nohup kate &

Após fechar konsole, pstree terá a seguinte aparência:

init-+
     |-kate---2*[{kate}]

e kate sobreviverão. :)

Uma alternativa é usar screen/tmux/byobu, o que manterá o Shell em execução, independente do terminal.

50
gertvdijk

Você pode executar o processo como este no terminal

setsid process

Isso executará o programa em uma nova sessão. Conforme explicado http://hanoo.org/index.php?article=run-program-in-new-session-linux

31
hanoo

Embora todas as sugestões funcionem bem, descobri que minha alternativa é usar screen, um programa que configura um terminal virtual na tela.

Você pode considerar iniciá-lo com screen -S session_name. A tela pode ser instalada em praticamente todos os derivados Linux e Unix. Batendo Ctrl+A e (minúscula) C iniciará uma segunda sessão. Isso permitiria alternar entre a sessão inicial pressionando Ctrl+A e  ou a sessão mais recente pressionando Ctrl+A e 1. Você pode ter até dez sessões em um terminal. Eu costumava iniciar uma sessão no trabalho, ir para casa, fazer ssh na minha máquina de trabalho e depois invocar screen -d -R session_name. Isso irá reconectá-lo a essa sessão remota.

10
apolinsky

Eu prefiro:

(Nome do aplicativo e)

por exemplo: [email protected]:~$ (chromium-browser &)

Certifique-se de usar parênteses ao digitar o comando!

8
daGo

Eu tenho um script para:

  • Executar comandos arbitrários em segundo plano

  • Impeça que sejam mortos com a janela do terminal

  • Suprimir sua saída

  • Lida com o status de saída

Eu o uso principalmente para gedit, evince, inkscape etc, que possuem muitas saídas irritantes de terminal. Se o comando terminar antes de TIMEOUT, o status de saída do Nohup será retornado em vez de zero.

#!/bin/bash

TIMEOUT=0.1

#use Nohup to run the command, suppressing its output and allowing the terminal to be closed
#also send Nohup's output to /dev/null, supressing Nohup.out
#run Nohup in the background so this script doesn't block
Nohup "${@}" >/dev/null 2>&1 &
Nohup_PID=$!

#kill this script after a short time, exiting with success status - command is still running
#this is needed as there is no timeout argument for `wait` below
MY_PID=$$
trap "exit 0" SIGINT SIGTERM
sleep $TIMEOUT && kill $MY_PID 2>/dev/null & #ignore "No such process" error if this exits normally

#if the command finishes before the above timeout, everything may be just fine or there could have been an error
wait $Nohup_PID
Nohup_STATUS=$?
#print an error if there was any. most commonly, there was a typo in the command
[ $Nohup_STATUS != 0 ] && echo "Error ${@}"
#return the exit status of Nohup, whatever it was
exit $Nohup_STATUS

exemplos...

>>> run true && echo success || echo fail
success
>>> run false && echo success || echo fail
Error false
fail
>>> run sleep 1000 && echo success || echo fail
success
>>> run notfound && echo success || echo fail
Error notfound
fail
7
jozxyqk

A maneira exclusiva do Shell de fazer tudo isso é fechar o stdin e colocar em segundo plano o comando:

command <&- & 

Então não será encerrado quando você sair do Shell. Redirecionar stdout é uma boa opção opcional.

A desvantagem é que você não pode fazer isso depois do fato.

7
w00t

Você pode definir um processo (PID) para não receber um sinal HUP ao sair e fechar a sessão do terminal. Use o seguinte comando:

Nohup -p PID
4
tony

Indiscutivelmente semelhante ao resposta oferecida por apolinsky , eu uso uma variante em screen. O comando Vanilla é assim

screen bash -c 'long_running_command_here; echo; read -p "ALL DONE:"'

A sessão pode ser desconectada com Ctrl ACtrl D e reconectado no caso simples com screen -r. Eu tenho isso envolto em um script chamado session que mora no meu PATH pronto para acesso conveniente:

#!/bin/bash
#
if screen -ls | awk '$1 ~ /^[1-9][0-9]*\.'"$1"'/' >/dev/null
then
    echo "WARNING: session is already running (reattach with 'screen -r $1')" >&2
else
    exec screen -S "$1" bash -c "[email protected]; echo; echo '--------------------'; read -p 'ALL DONE (Enter to exit):'"
    echo "ERROR: 'screen' is not installed on this system" >&2
fi
exit 1

Isso só funciona quando você sabe com antecedência que deseja desconectar um programa. Ele não prevê que um programa já esteja em execução seja desconectado.

3
roaima

Da mesma forma que outras respostas postadas anteriormente, pode-se transferir um processo em execução para usar a "tela" retrospectivamente, graças a reptyr e depois fechar o terminal. As etapas são descritas neste post . Os passos a seguir são:

  1. Suspender o processo
  2. Retomar o processo em segundo plano
  3. Negar o processo
  4. Iniciar uma sessão de tela
  5. Encontre o PID do processo
  6. Use reptyr para assumir o processo
2
user308879