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

313

À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?

Mateus
fonte
4
Não é uma instalação padrão em todas as distros, mas a tela é sua amiga: en.wikipedia.org/wiki/GNU_Screen
Zayne S Halsall
Para quem enfrenta o mesmo problema: lembre-se de que, mesmo que você digite yourExecutable &e as saídas continuem aparecendo na tela e Ctrl+Cnão pare nada, basta digitar cegamente disown;e pressionar Entermesmo que a tela esteja rolando com saídas e você não possa ver o que você está digitando. O processo será contestado e você poderá fechar o terminal sem que o processo acabe.
Nav
Você pode usar o multiplexador de tela como o tmux . Está disponível via apt-get em máquinas ubuntu
Himanshu

Respostas:

311

Um dos 2 a seguir deve funcionar:

$ nohup redshift &

ou

$ redshift &
$ disown

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

Steven D
fonte
5
O segundo ( redshift & disown) funcionou para mim no Ubuntu 10.10. Parece funcionar bem, colocando tudo em uma linha. Existe alguma razão para eu não fazer isso?
Matthew
4
@ Matthew O primeiro deve funcionar bem também, ele simplesmente não funciona como o segundo (você possivelmente deseja nohup redshift &, o mesmo ocorre). E colocar o segundo em uma linha é bom, apesar de geralmente você se separar de ;( redshift &; disown)
Michael Mrozek
10
@ Michael: Ambos ;e &são separadores de comando e têm precedência igual. A única diferença é a execução síncrona versus assíncrona (respectivamente). Não há necessidade de usar &;apenas a preferência &(funciona, mas é um pouco redundante).
precisa
4
boa resposta, pode-se acrescentar que seria uma boa idéia para redirecionar stdout e stderr para que o terminal não vai ser spam com saída de depuração
Kim
12
Além disso, redshift &!negará o desvio para o vermelho imediatamente.
143

Se o seu programa estiver em execução, você pode pausá-lo Ctrl-Z, puxá-lo para segundo plano bge, em seguida disown, da seguinte maneira:

$ sleep 1000
^Z
[1]+  Stopped                 sleep 1000
$ bg
$ disown
$ exit
Stefan
fonte
3
depois de rejeitado, como posso ler novamente o stdout do processo em execução?
Necktwi
1
Isto não funcionou para mim por alguma razão (centos)
Ian
Como matar o processo após este procedimento?
Palak Darji
2
@necktwi disownnão desconecta stdout ou stderr. No entanto nohup, assim como >/dev/null(desconecte a saída padrão), 2>/dev/null(desconecte o erro padrão). ( disown) Desconecta o controle do trabalho.
CTRL-ALT-DELOR
45

A 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 kateprocesso desanexado konsolequando você termina konsole, use nohupcom o comando, como este:

nohup kate &

Após o fechamento konsole, pstreeficará assim:

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

e katevai sobreviver. :)

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

gertvdijk
fonte
Eu tive problemas com os métodos rejeitados. No momento, isso está funcionando para mim, de forma positiva. Eu também gosto disso porque eu posso tail -f nohup.out para ver o que está acontecendo, mas não se preocupe com a minha sessão não
Ian
27

Você pode executar o processo como este no terminal

setsid process

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

hanoo
fonte
1
O que você vê como as vantagens do setsid sobre o nohup?
itsbruce
1
1) Não imprime uma mensagem irritante sobre nohup.out. 2) Ele não permanece na lista de tarefas do seu shell, portanto não atrapalha a saída de jobs.
Mikel
Esta é a única solução que funcionou com scripts executados no lxterminal, inicia o pcmanfm e exit (com o setsid, o terminal pode fechar enquanto o pcmanfm continua em execução). Muito obrigado!
desgua
9

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

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

apolinsky
fonte
screen -d -m commandirá iniciá-lo dentro da tela já desanexada: ~# screen -d -m top ~# screen -ls There is a screen on: 10803..Server-station (Detached) 1 Socket in /root/.screen. ~# screen -x .... e você está dentro.
Dr. Alexander
7

A maneira apenas de 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.

w00t
fonte
Eu tentei no ubuntu. O terminal de assassinatos também encerrou o processo lançado. Alguma idéia de por que esse poderia ser o caso?
Ashok Koyi
7

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, etc evince, inkscapetodos com muita saída terminal irritante. Se o comando terminar antes 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
jozxyqk
fonte
7

Eu prefiro:

(Nome da Aplicação &)

por exemplo: linux@linux-desktop:~$ (chromium-browser &)

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

daGo
fonte
1
Fechando o terminal vai matar o processo , o que exatamente o OP (e eu, vindo, assim, aqui) quer é evitar
gromit190
1
Provavelmente você tem um comando rápido que eu usei na minha resposta sem parênteses; se assim for, fechar o terminal matará o processo, caso contrário, NÃO acontecerá. Já editei a solução acima para esclarecer.
daGo 30/11/16
trabalhar para mim, tnx
noadev
Eu estou querendo saber por que isso não recebeu mais votos positivos. nohupevita qualquer saída tty e na verdade eu só queria redirecionar a saída para um arquivo e isso impedia que essa fosse a melhor solução para mim.
Redanimalwar #
4

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
Tony
fonte
3

Indiscutivelmente semelhante à resposta oferecida por apolinsky , 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 Ctrl ACtrl De reconectada no caso simples com screen -r. Eu tenho isso envolto em um script chamado sessionque mora no meu PATHpronto 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 "$@; 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á em execução seja desconectado.

roaima
fonte
2

Da mesma forma que outras respostas postadas anteriormente, pode-se transferir um processo em execução para usar a "tela" retrospectivamente, graças ao reptyr e depois fechar o terminal. Os passos estão descritos nesta publicação . 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
user308879
fonte