Como desmembrar completamente um processo do Terminal?

278

Eu uso o Tilda (terminal drop-down) no Ubuntu como meu "comando central" - praticamente da mesma forma que os outros podem usar o GNOME Do, Quicksilver ou Launchy.

No entanto, estou com dificuldades para separar completamente um processo (por exemplo, Firefox) do terminal em que foi lançado - ou seja, impedir que tal processo (não) filho

  • é encerrado ao fechar o terminal de origem
  • "polui" o terminal de origem via STDOUT / STDERR

Por exemplo, para iniciar o Vim em uma janela de terminal "apropriada", 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 parece não funcionar).

    
por slhck 23.03.2009 / 12:59

18 respostas

313

Primeiro de tudo; Uma vez que você iniciou um processo, você pode fazer o background parando-o primeiro (tecle Ctrl - Z ) e então digitando bg para deixá-lo retomar em segundo plano. Agora é um "trabalho" e seu stdout / stderr / stdin ainda está conectado ao seu terminal.

Você pode iniciar um processo como antecedido imediatamente anexando um "&" até o fim:

firefox &

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

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

Algumas informações adicionais:

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

disown é um bash embutido que remove um trabalho de shell da lista de trabalhos do shell. O que isso basicamente significa é que você não pode mais usar fg , bg , mas o mais importante, quando você fechar seu shell, ele não irá mais travar ou enviar um SIGHUP para aquela criança. Ao contrário de nohup , disown é usado após o processo foi iniciado e em segundo plano.

O que você não pode fazer é alterar o stdout / stderr / stdin de um processo depois de tê-lo lançado. Pelo menos não da casca. Se você iniciar seu processo e informar que seu stdout é seu terminal (que é o que você faz por padrão), então esse processo é configurado para saída para seu terminal. Seu shell não tem nenhum negócio com a configuração do FD dos processos, que é puramente 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 ser lembrado. Mas para processos interativos que você começa, mas esqueceu de silenciar ( firefox < /dev/null &>/dev/null & ) você não pode fazer muito, realmente.

Eu recomendo que você receba o GNU screen . Com a tela, você pode apenas fechar seu 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ê está usando.

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

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

Isso provavelmente não é o que você quer porque -e só aceita um argumento. Use $1 para mostrar que seu script pode manipular apenas um argumento.

É realmente difícil obter vários argumentos funcionando corretamente no cenário que você forneceu (com gnome-terminal -e ) porque -e aceita apenas um argumento, que é uma cadeia de comando do shell. Você teria que codificar seus argumentos em um. O melhor e mais robusto, mas um tanto áspero, é assim:

gnome-terminal -e "vim $(printf "%q " "$@")"
    
por 23.03.2009 / 14:18
193
nohup cmd &

nohup desanexa o processo completamente (daemoniza)

    
por 23.03.2009 / 13:17
53

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

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

    
por 23.03.2009 / 13:05
36

Ao ler essas respostas, fiquei com a impressão inicial de que a emissão de nohup <command> & seria suficiente. Executando zsh no gnome-terminal, descobri que nohup <command> & não impediu que meu shell matasse processos filhos na saída. Embora nohup seja útil, especialmente com shells não interativos, ele só garante esse comportamento se o processo filho não redefinir seu manipulador para o sinal SIGHUP .

No meu caso, nohup deve ter impedido que sinais de desligamento atinjam o aplicativo, mas o aplicativo filho (neste caso, VMWare Player) estava redefinindo seu manipulador SIGHUP . Como resultado, quando o emulador de terminal é encerrado, ele ainda pode matar seus subprocessos. Isso só pode ser resolvido, no meu conhecimento, garantindo que o processo seja removido da tabela de jobs do shell. Se nohup for sobrescrito com um shell embutido, como às vezes é o caso, isso pode ser suficiente, no entanto, no caso de não ser ...

disown é um shell embutido em bash , zsh e ksh93 ,

<command> &
disown

ou

<command> &; disown

se você preferir os one-liners. Isso geralmente tem o efeito desejável de remover o subprocesso da tabela de jobs. Isso permite que você saia do emulador de terminal sem acidentalmente sinalizar o processo filho. Não importa como o manipulador SIGHUP se parece, isso não deve matar seu processo filho.

Após a rejeição, o processo ainda é um filho do seu emulador de terminal (reproduza com pstree se você quiser ver isso em ação), mas após o emulador de terminal sair, você deve vê-lo anexado ao processo init. Em outras palavras, tudo é como deveria ser, e como você presumivelmente quer que seja.

O que fazer se o seu shell não suportar disown ? Eu defendo strongmente a mudança para uma que o faça, mas, na ausência dessa opção, você tem algumas escolhas.

  1. screen e tmux podem resolver este problema, mas eles são soluções de peso muito mais pesado, e eu não gosto de ter que executá-los para uma tarefa tão simples. Eles são muito mais adequados para situações em que você deseja manter um tty, normalmente em uma máquina remota.
  2. Para muitos usuários, pode ser desejável ver se o seu shell suporta um recurso como setopt nohup do zsh. Isso pode ser usado para especificar que SIGHUP não deve ser enviado para os trabalhos na tabela de jobs quando o shell sair. Você pode aplicar isso apenas antes de sair do shell ou adicioná-lo à configuração do shell, como ~/.zshrc , se desejar usá-lo sempre.
  3. Encontre uma maneira de editar a tabela de trabalhos. Não consegui encontrar uma maneira de fazer isso em tcsh ou csh , o que é um pouco perturbador.
  4. Escreva um pequeno programa em C para separar e exec() . Esta é uma solução muito pobre, mas a fonte deve consistir apenas em uma dúzia de linhas. Você pode então passar comandos como argumentos de linha de comando para o programa C e, assim, evitar uma entrada específica do processo na tabela de jobs.
por 22.01.2014 / 18:08
24
  1. nohup $ COMMAND &

  2. $ COMMAND & negar

  3. comando setsid

Estou usando o número 2 há muito tempo, mas o número 3 também funciona. Além disso, o disown possui um sinalizador 'nohup' de '-h', pode rejeitar todos os processos com '-a' e pode rejeitar todos os processos em execução com '-ar'.

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

Espero que isso ajude!

    
por 25.08.2015 / 16:39
9

Acho que a tela pode resolver seu problema

    
por 25.03.2009 / 02:51
8

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

Compare isso:

> 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 jobs, mas ainda está vinculado ao terminal; se você logou neste nó via 'ssh', tentar sair ainda irá travar o processo ssh.

    
por 23.03.2009 / 15:55
6

Para desassociar o comando tty shell run através da sub-shell para, por exemplo,

(comando) &

Quando a saída usou o terminal fechado, mas o processo ainda está ativo.

verifique -

(sleep 100) & exit

Abra outro terminal

ps aux | grep sleep

O processo ainda está vivo.

    
por 07.08.2012 / 07:18
6

Resposta mais simples e correta para o bash:

command & disown

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

    
por 05.05.2017 / 13:55
5

A criação de planos e o primeiro plano de um trabalho provavelmente são uma das primeiras coisas que todo administrador do Unix deve saber.

Veja como é feito com o bash:

./script.sh
# suspend process
{ctrl-Z}
# background process
bg
# list all backgrounded jobs
jobs
# bring it back to foreground
fg
    
por 23.05.2013 / 01:00
4

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

    
por 23.03.2009 / 13:03
2

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

    
por 23.03.2009 / 13:10
1

No meu .bashrc, eu tenho essas funções exatamente para esse propósito:

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

function dos() {
    # run_disowned and silenced

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

Prefixe um comando com dos para executá-lo desconectado do terminal.

A função é escrita para trabalhar com bash e zsh .

    
por 14.06.2015 / 19:53
1

Adicione isso ao bashrc / zshrc:

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

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

detach gedit ~/.zshrc
    
por 05.02.2018 / 17:14
0

Encontrei no Mac OS X que preciso usar tanto nohup AND disown para garantir que o processo filho não seja demolido com o terminal.

    
por 19.06.2010 / 18:46
0

Eu uso o seguinte script para fazer isso. Ele interrompe o processo de impressão para o terminal, desanexa com nohup e 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
>>>
    
por 21.09.2014 / 06:42
-1

Muitas respostas sugeriram o uso de nohup . Eu prefiro sugerir o uso de pm2 . Usar 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 pm2 você precisa baixar npm . Para sistema baseado em Debian

sudo apt-get install npm

e para o Redhat

sudo yum install npm

Ou você pode seguir estas instruções . Depois de instalar o npm use-o para instalar o pm2

npm install pm2@latest -g

Quando terminar, você poderá iniciar sua inscrição

$ 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 processos, 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 os processos usando o nome do aplicativo ou o ID 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>

Arquivos de log podem ser encontrados em

$HOME/.pm2/logs #contain all applications logs
    
por 15.02.2017 / 05:16
-1

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

    
por 05.04.2017 / 15:47