Como desanexar um processo inteiramente do Terminal?

304

Eu uso o Tilda (terminal suspenso) no Ubuntu como minha "central de comandos" - da mesma forma que outras pessoas podem usar o GNOME Do, Quicksilver ou Launchy.

No entanto, estou lutando para desanexar completamente um processo (por exemplo, Firefox) do terminal do qual foi lançado - ou seja, impedir que esse processo (não) filho

  • termina quando fecha o terminal de origem
  • "polui" o terminal de origem via STDOUT / STDERR

Por exemplo, para iniciar o Vim em uma janela de terminal "adequada", tentei um script simples como o seguinte:

exec gnome-terminal -e "vim $@" &> /dev/null &

No entanto, isso ainda causa poluição (também, passar um nome de arquivo não parece funcionar).

slhck
fonte
1
Essa também é uma boa pergunta. Eu acho que é justo considerar Bash uma linguagem de programação - embora de fato o âmbito desta questão é provavelmente mais no lado do sysadmin ...
Esta é uma duplicata de esta questão stackoverflow.com/questions/285015/...
Dana the Sane
Seu caso de uso não descreve o desapego completo, por si só.
jiggunjer

Respostas:

344

Em primeiro lugar; Depois de iniciar um processo, você pode colocá-lo em segundo plano, primeiro parando-o (pressionar Ctrl- Z) e digitando bgpara deixá-lo retomar em segundo plano. Agora é um "trabalho" e seu stdout/ stderr/ stdinainda está conectado ao seu terminal.

Você pode iniciar um processo como segundo plano imediatamente anexando um "&" ao final dele:

firefox &

Para executá-lo em segundo plano silenciado, use o seguinte:

firefox </dev/null &>/dev/null &

Algumas informações adicionais:

nohupé um programa que você pode usar para executar seu aplicativo, de modo que seu stdout / stderr possa ser enviado para um arquivo e que o fechamento do script pai não SIGHUP o filho. No entanto, você precisa ter a previsão de usá-lo antes de iniciar o aplicativo. Por causa da maneira como nohupfunciona, você não pode simplesmente aplicá-lo a um processo em execução .

disowné um bash interno que remove um trabalho de shell da lista de trabalhos do shell. O que isto significa, basicamente, é que você não pode usar fg, bgno mais, mas o mais importante, quando você fecha o shell não irá travar ou enviar uma SIGHUPpara aquela criança mais. Ao contrário nohup, disowné usado após o processo ser iniciado e em segundo plano.

O que você não pode fazer é alterar o stdout / stderr / stdin de um processo depois de iniciá-lo. Pelo menos não da casca. Se você iniciar o seu processo e informar que o stdout é o seu terminal (que é o que você faz por padrão), esse processo está configurado para gerar saída para o seu terminal. Seu shell não se importa com a configuração de FD dos processos, isso é algo que o próprio processo gerencia. O processo em si pode decidir se deseja fechar seu stdout / stderr / stdin ou não, mas você não pode usar seu shell para forçá-lo a fazê-lo.

Para gerenciar a saída de um processo em segundo plano, você tem muitas opções de scripts, "nohup" provavelmente sendo o primeiro a se lembrar. Mas para processos interativos você inicia, mas esquece de silenciar ( firefox < /dev/null &>/dev/null &), na verdade não pode fazer muito.

Eu recomendo que você obtenha o GNU screen. Com a tela, você pode fechar o shell em execução quando a saída do processo se tornar um incômodo e abrir um novo ( ^Ac).


Ah, e a propósito, não use " $@" onde você estiver usando.

$@significa, $1, $2, $3..., que iria transformar o seu comando em:

gnome-terminal -e "vim $1" "$2" "$3" ...

Provavelmente não é isso que você quer, porque -e leva apenas um argumento. Use $1para mostrar que seu script pode lidar apenas com um argumento.

É realmente difícil fazer com que vários argumentos funcionem corretamente no cenário que você forneceu (com o gnome-terminal -e) porque -eleva apenas um argumento, que é uma sequência de comandos do shell. Você teria que codificar seus argumentos em um. A maneira melhor e mais robusta, mas bastante desajeitada, é a seguinte:

gnome-terminal -e "vim $(printf "%q " "$@")"
lhunath
fonte
Muito obrigado por isso! Infelizmente, só posso aceitar uma resposta. Acabei com "nohup $ @ &> / dev / null &" e "alias wvim = 'launch.sh gnome-terminal -x vim'"
20
Que resposta fantasticamente detalhada e informativa. +1
Teekin 19/10/11
1
@ Hi-Angel, quando você fecha um shell bash interativo, bash HUPs todos os trabalhos ativos. Quando você processa um processo, ele ainda é um trabalho, seja em segundo plano. Para removê-lo como um trabalho, use disown, o processo continuará vivo depois que você fechar o shell, pois o bash não o fará mais.
Lhunath
3
Já não está usando em $*vez de $@corrigir o problema das seqüências separadas?
S28
2
O que você não pode fazer é alterar o stdout / stderr / stdin de um processo depois de iniciá-lo. - não é exatamente verdade. Use reptyrpara isso.
Stefan Seidel
198
nohup cmd &

nohup desanexa completamente o processo (daemonizes)

dsm
fonte
5
Embora sucinto seja valioso, a integridade é mais valiosa. Embora o nohup seja um coreutil do GNU, uma resposta somente do bash (ou observação de que não existe um) seria apropriada aqui. Boa resposta, no entanto.
Expiação limitada
23
nohupapenas ignora o SIGHUPsinal. Ele executa o processo normalmente. Sem daemonização.
nemo
1
@nemo O que significa que o processo não é desanexado, mas seria desanexado (e filho de init) se o shell saísse ... certo?
Noldorin
@Noldorin Sim. Ignorar SIGHUP, que é enviado quando o shell é finalizado, deixará o processo filho em execução e será realocado para init.
31416
O @nemo nohup também silencia as entradas / saídas padrão. Siga com renúncia para desanexar completamente.
Jggunjer
60

Se você estiver usando bash, tente ; veja bash (1) .disown [jobspec]

Outra abordagem que você pode tentar é at now. Se você não é superusuário, sua permissão para uso atpode ser restrita.

Randy Proctor
fonte
"disown" não parece ser um comando interno do bash (não está disponível na minha máquina e eu uso o bash). "nohup", como Ben sugeriu, pode ser uma maneira muito melhor (e padrão) de fazer isso.
1
nunca pensei em usar "at", obrigado pela idéia!
cadrian
1
atdelegar execução a outra pessoa, eu gosto! +1
Ninsuo 12/04
1
Como ponto de referência, isso também funciona zsh.
Coderer
1
Além disso, disownnão parece ter o efeito desejado com gnome-terminal- disowned processos ainda estão mortos quando as saídas do terminal. Eu adoraria saber por que / como.
Kyle Strand
38

Lendo essas respostas, tive a impressão inicial de que a emissão nohup <command> &seria suficiente. Executando o zsh no gnome-terminal, descobri que nohup <command> &não impedia meu shell de matar processos filhos na saída. Embora nohupseja útil, especialmente com shells não interativos, apenas garante esse comportamento se o processo filho não redefinir seu manipulador para o SIGHUPsinal.

No meu caso, nohupdeveria ter impedido que sinais de interrupção chegassem ao aplicativo, mas o aplicativo filho (VMWare Player neste caso) estava redefinindo seu SIGHUPmanipulador. Como resultado, quando o emulador de terminal sai, ele ainda pode matar seus subprocessos. Isso só pode ser resolvido, que eu saiba, garantindo que o processo seja removido da tabela de tarefas do shell. Se nohupfor substituído por um shell incorporado, como às vezes é o caso, isso pode ser suficiente, no entanto, no caso de não ser ...


disowné um escudo embutido no bash, zshe ksh93,

<command> &
disown

ou

<command> &; disown

se você preferir one-liners. Isso tem o efeito geralmente desejável de remover o subprocesso da tabela de tarefas. Isso permite que você saia do emulador de terminal sem sinalizar acidentalmente o processo filho. Independentemente da SIGHUPaparência do manipulador, isso não deve matar o processo filho.

Após a rejeição, o processo ainda é filho do seu emulador de terminal (brinque com pstreese você quiser assistir a isso em ação), mas após a saída do emulador de terminal, você deverá vê-lo anexado ao processo de inicialização. Em outras palavras, tudo está como deveria ser e como você provavelmente quer que seja.

O que fazer se o seu shell não suportar disown? Eu seria altamente recomendável mudar para um que sim, mas, na ausência dessa opção, você tem algumas opções.

  1. screene tmuxpode resolver esse problema, mas são soluções muito mais pesadas e não gosto de executá-las para uma tarefa tão simples. Eles são muito mais adequados para situações nas quais você deseja manter um tty, normalmente em uma máquina remota.
  2. Para muitos usuários, pode ser desejável verificar se o seu shell suporta um recurso como o zsh setopt nohup. Isso pode ser usado para especificar que SIGHUPnão deve ser enviado para os trabalhos na tabela de trabalhos quando o shell sair. Você pode aplicar isso imediatamente antes de sair do shell ou adicioná-lo à configuração do shell como ~/.zshrcse você sempre o quisesse.
  3. Encontre uma maneira de editar a tabela de tarefas. Não consegui encontrar uma maneira de fazer isso no tcshou csh, o que é um pouco perturbador.
  4. Escreva um pequeno programa em C para executar e exec(). Essa é uma solução muito ruim, mas a fonte deve consistir apenas em algumas dezenas de linhas. Você pode passar comandos como argumentos da linha de comando para o programa C e, assim, evitar uma entrada específica do processo na tabela de tarefas.
Stephen Rosen
fonte
29
  1. nohup $COMMAND &
  2. $COMMAND & disown
  3. setsid command

Eu uso o número 2 há muito tempo, mas o número 3 funciona da mesma forma. Além disso, disownpossui um nohupsinalizador de -h, pode negar todos os processos -ae pode negar todos os processos em execução -ar.

O silenciamento é realizado por $COMMAND &>/dev/null.

Espero que isto ajude!

Mr. Minty Fresh
fonte
Curto e grosso; obrigado por este resumo muito útil!
Sheljohn 10/01
Não acredito que ainda recebo notificações para este post ...
Sr. Minty Fresh
9

Eu acho que a tela pode resolver seu problema


fonte
9

no tcsh (e talvez em outros shells também), você pode usar parênteses para desanexar o processo.

Compare isto:

> jobs # shows nothing
> firefox &
> jobs
[1]  + Running                       firefox

Para isso:

> jobs # shows nothing
> (firefox &)
> jobs # still shows nothing
>

Isso remove o firefox da lista de empregos, mas ainda está vinculado ao terminal; se você efetuou login neste nó via 'ssh', a tentativa de efetuar logout ainda trará o processo ssh.

Nathan Fellman
fonte
9

Resposta mais simples e correta para o bash:

command & disown

Você não precisa desanexar o processo do terminal, mas do shell.

ManuelSchneid3r
fonte
7

Para desassociar o tty shell, execute o comando através do sub-shell, por exemplo

(comando)&

Quando o terminal usado sair fechado, mas o processo ainda está ativo.

Verifica -

(sleep 100) & exit

Abra outro terminal

ps aux | grep sleep

O processo ainda está vivo.

jitendra
fonte
Isso é exatamente o que eu precisava. Eu estava tentando adicionar um atalho do console para texto sublime e ele funciona perfeitamente, eis o que eu acabei com: ("/ opt / Sublime Text 2 / sublime_text" $ @) &
Ron E
5

O background e o primeiro plano de um trabalho são provavelmente uma das primeiras coisas que todo administrador de sistemas Unix deve saber.

Aqui está como isso é feito com o bash:

./script.sh
# suspend process
{ctrl-Z}
# background process
bg
# list all backgrounded jobs
jobs
# bring it back to foreground
fg
djangofan
fonte
4

Você pode executar seu comando usando o comando nohup, desanexando seu processo e redirecionando as saídas para um determinado arquivo ... mas não tenho certeza de que é exatamente isso que você precisa.

Ben
fonte
Eu poderia jurar que havia tentado nohup antes de usar exec - mas aparentemente não corretamente, pois funciona assim: nohup gnome-terminal -e "vim $ @" &> / dev / null &
2

Experimente o daemon - deve estar disponível no seu amigável gerenciador de pacotes e cuidar de todas as maneiras de se desassociar do terminal.

ShiDoiSi
fonte
2

Basta adicionar isso no seu bashrc / zshrc:

detach() {
  "$@" 1>/dev/null 2>/dev/null &; disown
}

Então você pode executar comandos renegados como este:

detach gedit ~/.zshrc
B. Branchard
fonte
1

No meu .bashrc, tenho essas funções exatamente para esse fim:

function run_disowned() {
    "$@" & disown
}

function dos() {
    # run_disowned and silenced

    run_disowned "$@" 1>/dev/null 2>/dev/null
}

Prefixe um comando com dospara executá-lo desanexado do terminal.

A função foi escrita para trabalhar com bashe zsh.

ratos
fonte
1
Estou um pouco confuso sobre o porquê esta resposta utiliza uma função envolto em outro, quando seu suficiente para usar apenas uma função com o corpo assim: ( "$@" & disown) &> /dev/null. Ele também faz não muito sentido usar 1>e 2>, porque você está usando disown, o que significa que você está usando bash, e em bash você pode apenas fazer facilmente &>redirecionar ambos stdout e stderr
Sergiy Kolodyazhnyy
Eu tenho isso como duas funções porque (1) acho que é mais fácil ler dessa maneira e (2) preciso da run_disownedfuncionalidade em outros lugares nos meus arquivos de ponto. Você está certo sobre a &>coisa, é claro.
mic_e
0

Eu descobri no Mac OS X que preciso usar nohup AND disown para garantir que o processo filho não seja interrompido pelo terminal.

Aaron
fonte
0

Eu uso o seguinte script para fazer isso. Ele interrompe a impressão do processo no terminal, desconecta nohupe sai com o status de retorno se o comando terminar dentro do TIMEOUT.

#!/bin/bash

TIMEOUT=0.1

CMD=( "$@" )
#Could have some shortcuts here, e.g. replace "somefile.c" with "gedit somefile.c"

#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
#print the command for debugging and to see bash variable expansion
printf "%q " "${CMD[@]}"
echo
nohup "${CMD[@]}" >/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: $CMD"
#return the exit status of nohup, whatever it was
exit $NOHUP_STATUS

Exemplo de uso:

>>> run false
false
Error: false
>>> echo $?
1
>>> run true
true
>>> run sleep 10
sleep 10
>>>
jozxyqk
fonte
0

sudo apt install ucommon-utils

pdetach command

Ai está :)

d4rk4ng31
fonte
-1

Muitas respostas sugeriram o uso de nohup . Prefiro sugerir o uso do pm2 . O uso do pm2 sobre nohup tem muitas vantagens, como manter o aplicativo ativo, manter arquivos de log para aplicativos e muito mais outros recursos. Para mais detalhes, verifique isso .

Para instalar o pm2, você precisa fazer o download do npm . Para sistema baseado em Debian

sudo apt-get install npm

e para Redhat

sudo yum install npm

Ou você pode seguir estas instruções . Após instalar o npm, use-o para instalar o pm2

npm install pm2@latest -g

Feito isso, você pode iniciar seu aplicativo

$ pm2 start app.js              # Start, Daemonize and auto-restart application (Node)
$ pm2 start app.py              # Start, Daemonize and auto-restart application (Python)

Para monitoramento de processo, use os seguintes comandos:

$ pm2 list                      # List all processes started with PM2
$ pm2 monit                     # Display memory and cpu usage of each app
$ pm2 show [app-name]           # Show all informations about application

Gerencie processos usando o nome do aplicativo ou a identificação do processo ou gerencie todos os processos juntos:

$ pm2 stop     <app_name|id|'all'|json_conf>
$ pm2 restart  <app_name|id|'all'|json_conf>
$ pm2 delete   <app_name|id|'all'|json_conf>

Os arquivos de log podem ser encontrados em

$HOME/.pm2/logs #contain all applications logs
haccks
fonte
1
Usar um aplicativo NodeJS (versus um comando pequeno e robusto como nohup) para controlar processos unix parece ... realmente um exagero e, para ser sincero, um pouco estranho. Eu usaria o monit se você precisar da funcionalidade de reinicialização.
Sergio
@Sergio é sua escolha para usar aplicativos carentes.
haccks
Vários lançamentos foram feitos este ano (um há 4 dias), então não vejo como / por que você pode achar que o monit é um aplicativo obsoleto. @see mmonit.com/monit/changes
Sergio
Eu estava falando sobre nohup.
haccks
1
nohupé um comando POSIX padrão comum, portanto, a mesma observação: de nenhuma maneira é preterido. @see unix.com/man-page/posix/1p/nohup
Sergio
-1

Se seu objetivo é simplesmente iniciar um aplicativo de linha de comando sem manter a janela do terminal, tente executar o aplicativo depois de iniciar o terminal com alt-F2.

MattKelly
fonte