Como faço para colocar um processo já em execução nohup?

940

Eu tenho um processo que já está em execução há muito tempo e não deseja finalizá-lo.

Como colocá-lo em nohup (ou seja, como faço para continuar funcionando mesmo se eu fechar o terminal?)

flybywire
fonte
29
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

Respostas:

1367

Usando o Job Control do bash para enviar o processo para o segundo plano:

  1. Ctrl+ Zpara parar (pausar) o programa e voltar ao shell.
  2. bg para executá-lo em segundo plano.
  3. disown -h [job-spec]onde [job-spec] é o número do trabalho (como %1no primeiro trabalho em execução; encontre o seu número com o jobscomando) para que o trabalho não seja eliminado quando o terminal for fechado.

fonte
38
Como a questão era como "colocá-lo em nohup", disown -htalvez seja a resposta mais exata: "fazer com que o renomado se comporte mais como nohup (ou seja, os trabalhos permanecerão na árvore de processos do shell atual até você sair do shell)" Isso permite que você veja todos os trabalhos que esse shell iniciou ". (de [ quantprinciple.com/invest/index.php/docs/tipsandtricks/unix/… )
Dr. Jan-Philip Gehrcke
8
Como recupero o trabalho mais tarde? Eu posso vê-lo rodando usando ps -e.
Paulo Casaretto
26
Você não pode ver a saída de um trabalho depois que a disown, disown torna um processo um daemon, o que significa que a entrada / saída padrão é redirecionada para / dev / null. Então, se você pretende renegar um trabalho, é melhor começar com login em um arquivo, por exemplomy_job_command | tee my_job.log
rustyx
8
é possível de alguma forma fazer algo como 'my_job_command | tee my_job.log ' depois que o comando já estiver em execução?
Arod #
23
disowndesassocia quaisquer tubos do processo. Para recolocar os tubos, use gdbcomo descrito neste tópico . Mais especificamente, este post .
Mbrownnyc
185

Suponha que, por algum motivo, o Ctrl+ Ztambém não esteja funcionando, vá para outro terminal, encontre o ID do processo (usando ps) e execute:

kill -SIGSTOP PID 
kill -SIGCONT PID

SIGSTOPsuspenderá o processo e SIGCONTretomará o processo em segundo plano. Portanto, agora, fechar os dois terminais não interromperá o processo.

Pungs
fonte
10
Sim, isso é um problema do sistema operacional, o kill não funciona com o Cygwin no Windows.
Pungs
6
Também é muito útil se o trabalho for iniciado a partir de outra sessão ssh.
Amir Ali Akbari
5
Lembre-se de fazer disown %1o primeiro terminal antes de fechá-lo.
fred
1
Isso é útil desde que iniciei uma interface gráfica com um console (no meu caso, iniciei no konsole kwinapós uma falha sem pensar nas consequências). Então, se eu parasse o kwin, tudo teria congelado e eu não tinha possibilidade de correr bg!
Michele
@fred Eu não fiz isso e parecia continuar funcionando. Possível ou atingi o PID errado?
219166 Ninguém escreveu:
91

O comando para separar um trabalho em execução do shell (= torna nohup) é disowne um comando shell básico.

De bash-manpage (man bash):

renegar [-ar] [-h] [jobspec ...]

Sem opções, cada especificação de trabalho é removida da tabela de tarefas ativas. Se a opção -h for fornecida, cada jobpec não será removido da tabela, mas será marcado para que SIGHUP não seja enviado para o job se o shell receber um SIGHUP. Se nenhuma especificação de trabalho estiver presente e nem a opção -a nem a -r forem fornecidas, a tarefa atual será usada. Se nenhuma especificação de trabalho for fornecida, a opção -a significa remover ou marcar todas as tarefas; a opção -r sem um argumento jobspec restringe a operação à execução de jobs. O valor de retorno é 0, a menos que um jobpec não especifique um trabalho válido.

Isso significa que um simples

disown -a

removerá todos os trabalhos da tabela de trabalhos e os tornará nohup

serioys sam
fonte
9
disown -aremove todos os trabalhos. Um simples disownremove apenas o trabalho atual. Como a página de manual na resposta diz.
Rune Schjellerup Philosof
73

Estas são boas respostas acima, eu só queria adicionar um esclarecimento:

Você não pode dar disownum pid ou processo, disownum emprego, e essa é uma distinção importante.

Um trabalho é algo que é uma noção de um processo anexado a um shell; portanto, você deve lançar o trabalho em segundo plano (não suspendê-lo) e depois rejeitá-lo.

Questão:

%  jobs
[1]  running java 
[2]  suspended vi
%  disown %1

Veja http://www.quantprinciple.com/invest/index.php/docs/tipsandtricks/unix/jobcontrol/ para uma discussão mais detalhada sobre o Unix Job Control.

Q Caldeira
fonte
48

Infelizmente, disowné específico do bash e não está disponível em todas as conchas.

Certos tipos de Unix (por exemplo, AIX e Solaris) têm uma opção no nohuppróprio comando que pode ser aplicada a um processo em execução:

nohup -p pid

Veja http://en.wikipedia.org/wiki/Nohup

Dale
fonte
Somente para AIXe Solaris. "As versões AIX e Solaris do nohup têm uma opção -p que modifica um processo em execução para ignorar futuros sinais SIGHUP. Diferentemente do built-in desown acima descrito, o nohup -p aceita IDs de processo.". Fonte
AlikElzin-kilaka
27

A resposta do nó é realmente ótima, mas deixou em aberto a questão de como o stdout e o stderr podem ser redirecionados. Encontrei uma solução em Unix e Linux , mas também não está completa. Gostaria de mesclar essas duas soluções. Aqui está:

Para o meu teste, criei um pequeno script bash chamado loop.sh, que imprime o pid de si mesmo com um minuto de sono em um loop infinito.

$./loop.sh

Agora obtenha o PID desse processo de alguma forma. Geralmente ps -C loop.shé bom o suficiente, mas é impresso no meu caso.

Agora podemos mudar para outro terminal (ou pressionar ^ Z e no mesmo terminal). Agora gdbdeve ser anexado a esse processo.

$ gdb -p <PID>

Isso interrompe o script (se estiver em execução). Seu estado pode ser verificado por ps -f <PID>, onde o STATcampo é 'T +' (ou no caso de ^ Z 'T'), o que significa (man ps (1))

    T Stopped, either by a job control signal or because it is being traced
    + is in the foreground process group

(gdb) call close(1)
$1 = 0

Fechar (1) retorna zero em caso de sucesso.

(gdb) call open("loop.out", 01102, 0600)
$6 = 1

Aberto (1) retorna o novo descritor de arquivo, se for bem-sucedido.

Esta abertura é igual a open(path, O_TRUNC|O_CREAT|O_RDWR, S_IRUSR|S_IWUSR). Em vez de O_RDWR O_WRONLYpoderia ser aplicado, mas /usr/sbin/lsofdiz 'u' para todos os manipuladores de arquivos std * ( FDcoluna), o que é O_RDWR.

Eu verifiquei os valores no arquivo de cabeçalho /usr/include/bits/fcntl.h.

O arquivo de saída pode ser aberto com O_APPEND, como nohupfaria, mas isso não é sugerido por man open(2)causa de possíveis problemas no NFS.

Se obtivermos -1 como valor de retorno, call perror("")imprima a mensagem de erro. Se precisarmos do errno, use o p errnocomando gdb.

Agora podemos verificar o arquivo recém-redirecionado. /usr/sbin/lsof -p <PID>impressões:

loop.sh <PID> truey    1u   REG   0,26        0 15008411 /home/truey/loop.out

Se quisermos, podemos redirecionar o stderr para outro arquivo, se quisermos usar call close(2)e call open(...)novamente usando um nome de arquivo diferente.

Agora o anexo bashprecisa ser liberado e podemos sair gdb:

(gdb) detach
Detaching from program: /bin/bash, process <PID>
(gdb) q

Se o script foi parado por gdboutro terminal, ele continua sendo executado. Podemos voltar ao terminal loop.sh. Agora, ele não grava nada na tela, mas executa e grava no arquivo. Temos que colocá-lo em segundo plano. Então pressione ^Z.

^Z
[1]+  Stopped                 ./loop.sh

(Agora estamos no mesmo estado em que ^Zfoi pressionado no início.)

Agora podemos verificar o estado do trabalho:

$ ps -f 24522
UID        PID  PPID  C STIME TTY      STAT   TIME CMD
<UID>    <PID><PPID>  0 11:16 pts/36   S      0:00 /bin/bash ./loop.sh
$ jobs
[1]+  Stopped                 ./loop.sh

Portanto, o processo deve estar em execução em segundo plano e desconectado do terminal. O número na jobssaída do comando entre colchetes identifica o trabalho dentro bash. Podemos usar os seguintes bashcomandos internos, aplicando um sinal '%' antes do número do trabalho:

$ bg %1
[1]+ ./loop.sh &
$ disown -h %1
$ ps -f <PID>
UID        PID  PPID  C STIME TTY      STAT   TIME CMD
<UID>    <PID><PPID>  0 11:16 pts/36   S      0:00 /bin/bash ./loop.sh

E agora podemos sair da festança de chamadas. O processo continua em execução em segundo plano. Se sairmos do seu PPID, tornar-se 1 (processo init (1)) e o terminal de controle se tornar desconhecido.

$ ps -f <PID>
UID        PID  PPID  C STIME TTY      STAT   TIME CMD
<UID>    <PID>     1  0 11:16 ?        S      0:00 /bin/bash ./loop.sh
$ /usr/bin/lsof -p <PID>
...
loop.sh <PID> truey    0u   CHR 136,36                38 /dev/pts/36 (deleted)
loop.sh <PID> truey    1u   REG   0,26     1127 15008411 /home/truey/loop.out
loop.sh <PID> truey    2u   CHR 136,36                38 /dev/pts/36 (deleted)

COMENTE

O material gdb pode ser automatizado, criando um arquivo (por exemplo, loop.gdb) contendo os comandos e executado gdb -q -x loop.gdb -p <PID>. Meu loop.gdb fica assim:

call close(1)
call open("loop.out", 01102, 0600)
# call close(2)
# call open("loop.err", 01102, 0600)
detach
quit

Ou pode-se usar o seguinte liner:

gdb -q -ex 'call close(1)' -ex 'call open("loop.out", 01102, 0600)' -ex detach -ex quit -p <PID>

Espero que esta seja uma descrição bastante completa da solução.

TrueY
fonte
Muito informativo e provavelmente funcionará bem em casos simples. Mas esteja avisado, casos mais complexos podem falhar miseravelmente. Eu tinha um desses hoje: meu processo gerou outro processo que produziu a saída (presumivelmente para stderr), mas que stdout se conectou à comunicação com seu mestre. Redirecionar os DFs mestres não teve efeito porque a criança herdou o stderr e o fechamento do stdout da criança falhou com o mestre que estava esperando na outra extremidade do tubo. X- A Bettern conhece bem seus processos antes de tentar isso.
cmaster - reinstate monica
@cmaster Você pode verificar se um identificador é redirecionado usando lsof(o nome do identificador de arquivo pipenão é igual a /dev/pts/1) ou por ls -l /proc/<PID>/fd/<fd>(isso mostra o link simbólico do identificador). Além disso, os subprocessos ainda não podem ter saídas redirecionadas, que devem ser redirecionadas para um arquivo.
TrueY 23/07/2015
7

Para enviar o processo em execução para o nohup ( http://en.wikipedia.org/wiki/Nohup )

nohup -p pid , não funcionou para mim

Então eu tentei os seguintes comandos e funcionou muito bem

  1. Execute alguns SOMECOMMAND, digamos /usr/bin/python /vol/scripts/python_scripts/retention_all_properties.py 1.

  2. Ctrl+ Zpara parar (pausar) o programa e voltar ao shell.

  3. bg para executá-lo em segundo plano.

  4. disown -h para que o processo não seja interrompido quando o terminal fechar.

  5. Digite exitpara sair do shell, porque agora você pode prosseguir, pois a operação será executada em segundo plano em seu próprio processo, para que não esteja vinculada a um shell.

Esse processo é equivalente à execução nohup SOMECOMMAND.

minhas23
fonte
3

No meu sistema AIX, tentei

nohup -p  processid>

Isso funcionou bem. Ele continuou a executar o meu processo, mesmo depois de fechar as janelas do terminal. Nós temos o ksh como shell padrão para que os comandos bge disownnão funcionem.

hóspede
fonte
2
  1. ctrl+ z - isso fará uma pausa no trabalho (não será cancelado!)
  2. bg - isso colocará o trabalho em segundo plano e retornará ao processo em execução
  3. disown -a - isso cortará todo o anexo com o trabalho (para que você possa fechar o terminal e ele ainda funcione)

Essas etapas simples permitirão fechar o terminal enquanto mantém o processo em execução.

Ele não será colocado nohup(com base no meu entendimento da sua pergunta, você não precisa dela aqui).

Alper t. Turker
fonte
Penso que o comportamento de renegar -a é cortar o apego em todos os trabalhos. No entanto, ele não desligamento dos dutos stdin / stdout, o que significa que o processo ainda vai tentar escrever (/ Read) a partir do terminal
Kelthar
-2

Isso funcionou para mim no Ubuntu linux enquanto estava no tcshell.

  1. CtrlZ pausar

  2. bg executar em segundo plano

  3. jobs para obter o número do trabalho

  4. nohup %n onde n é o número do trabalho

eshaya
fonte
2
Não, não funciona:nohup: failed to run command '%1': No such file or directory
Dunatotatos