2009-03-23 11:59:25 +0000 2009-03-23 11:59:25 +0000
311
311

Como é que eu separo um processo do Terminal, inteiramente?

Eu uso o Tilda (terminal drop-down) no Ubuntu como a minha “central de comando” - basicamente da forma como outros podem usar o GNOME Do, Quicksilver ou Launchy.

No entanto, estou a lutar para separar completamente um processo (por exemplo, Firefox) do terminal de onde foi lançado - ou seja evitar que esse processo (não)infantil

  • seja terminado ao fechar o terminal de origem
  • “polui” o terminal de origem via STDOUT/STDERR

Por exemplo, para iniciar o Vim numa janela de terminal “própria”, 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 ficheiro não parece funcionar).

Respostas (18)

355
355
355
2009-03-23 13:18:35 +0000

Em primeiro lugar; uma vez iniciado um processo, pode primeiro pará-lo em segundo plano (clique em Ctrl-Z) e depois digitar bg para que seja retomado em segundo plano. É agora um “trabalho”, e os seus stdout/stderr/stdin ainda estão ligados ao seu terminal.

Pode iniciar imediatamente um processo em segundo plano anexando um “&” ao final do mesmo:

firefox &

Para o executar em segundo plano silenciado, use o seguinte:

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

Algumas informações adicionais:

nohup é um programa que pode utilizar ** para executar a sua aplicação com**, de modo a que a sua stdout/stderr possa ser enviada para um ficheiro e de modo a que o fecho do script dos pais não SIGHUPe a criança. No entanto, precisa de ter tido a previsão para o ter utilizado antes de iniciar a aplicação. Devido à forma como o nohup funciona, não pode simplesmente aplicá-lo a um processo em execução.

disown é uma construção bash que remove um trabalho da shell da lista de trabalhos da shell. O que isto basicamente significa é que já não pode usar o fg, bg nele, mas mais importante, quando fecha a sua shell já não é pendurado ou envia um SIGHUP para aquela criança. Ao contrário do nohup, o disown é utilizado após o processo ter sido lançado e em segundo plano.

O que você can’t do, é alterar o stdout/stderr/stdin de um processo depois de o ter lançado. Pelo menos não a partir da casca. Se iniciar o seu processo e lhe disser que a stdout é o seu terminal (que é o que faz por defeito), então esse processo é configurado para sair para o seu terminal. A sua shell não tem negócios com a configuração FD dos processos, isso é apenas algo que o próprio processo gere. O processo em si pode decidir se fecha ou não a stdout/stderr/stdin, mas não pode usar a sua shell para o forçar a fazê-lo.

Para gerir a saída de um processo em segundo plano, tem muitas opções de scripts, sendo o “nohup” provavelmente o primeiro que lhe vem à cabeça. Mas para processos interactivos você começa mas esqueceu-se de silenciar (firefox < /dev/null &>/dev/null &) você não pode fazer muito, realmente.

Eu recomendo que você obtenha o GNU screen. Com o ecrã pode simplesmente fechar a sua shell quando a saída do processo se tornar um incómodo e abrir uma nova (^Ac).


Oh, e já agora, não use “$@” onde o está a usar.

$@ significa, $1, $2, $3 …, o que transformaria o 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 o seu script só pode lidar com um argumento.

É realmente difícil conseguir que vários argumentos funcionem correctamente no cenário que deu (com o gnome-terminal -e) porque -e leva apenas um argumento, que é uma string de comando shell. Você teria de codificar os seus argumentos num só. A melhor e mais robusta, mas um pouco desajeitada, maneira é assim:

gnome-terminal -e "vim $(printf "%q " "$@")"
202
202
202
2009-03-23 12:17:32 +0000
nohup cmd &

nohup separa completamente o processo (daemoniza-o)

62
62
62
2009-03-23 12:05:02 +0000

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

Outra abordagem que você pode tentar é at now. Se não é superutilizador, a sua permissão para utilizar o at pode ser restrita.

41
41
41
2014-01-22 17:08:16 +0000

Ao ler estas respostas, fiquei com a impressão inicial de que a emissão do nohup <command> & seria suficiente. Correndo zsh em gnome-terminal, descobri que o nohup <command> & não impedia que a minha concha matasse processos infantis à saída. Embora o nohup seja útil, especialmente com conchas não interactivas, só garante este comportamento se o processo da criança não reiniciar o seu manipulador para o sinal SIGHUP.

No meu caso, o nohup deveria ter evitado que os sinais de suspensão chegassem à aplicação, mas a aplicação da criança (VMWare Player neste caso) estava a reiniciar o seu manipulador SIGHUP. Como resultado, quando o emulador do terminal sair, ele ainda pode matar os seus subprocessos. Isto só pode ser resolvido, que eu saiba, assegurando que o processo é removido da tabela de tarefas da shell. Se o nohup for substituído por um shell construído, como por vezes acontece, isto pode ser suficiente, no entanto, no caso de não ser…


disown é um shell construído em bash, zsh, e ksh93,

<command> &
disown

ou

<command> &; disown

se preferir um shell construído em SIGHUP, pstree, e disown,

. Isto tem o efeito geralmente desejável de retirar o subprocesso da tabela de empregos. Isto permite-lhe sair do emulador de terminal sem sinalizar acidentalmente o processo da criança. Não importa o aspecto do screen handler, isto não deve matar o processo infantil.

Após a rejeição, o processo ainda é uma criança do seu emulador de terminal (brinque com o tmux se quiser ver isto em acção), mas após a saída do emulador de terminal, deve vê-lo ligado ao processo de init. Por outras palavras, tudo é como deve ser, e como você presumivelmente quer que seja.

O que fazer se a sua concha não suportar setopt nohup? Eu defenderia fortemente a mudança para uma que o faça, mas na ausência dessa opção, tem algumas escolhas.

  1. SIGHUP e ~/.zshrc podem resolver este problema, mas são soluções muito mais pesadas, e não gosto de as ter de executar para uma tarefa tão simples. São muito mais adequados para situações em que se pretende manter um tty, normalmente numa máquina remota.
  2. Para muitos utilizadores, pode ser desejável ver se o seu shell suporta uma capacidade como o zsh’s tcsh. Isto pode ser usado para especificar que o csh não deve ser enviado para os trabalhos na tabela de trabalhos quando a shell sai. Pode aplicar isto mesmo antes de sair da shell, ou adicioná-lo à configuração da shell como o exec() se o quiser sempre ligado.
  3. Encontre uma forma de editar a tabela de tarefas. Não consegui encontrar uma forma de fazer isto no &007 ou no &007, o que é um pouco perturbador.
  4. Escreva um pequeno programa em C para bifurcar e &007. Esta é uma solução muito pobre, mas a fonte deve consistir apenas em duas dúzias de linhas. 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 trabalhos.
30
30
30
2015-08-25 14:39:31 +0000
  1. nohup $COMMAND &
  2. $COMMAND & disown
  3. setsid command

Tenho usado o número 2 há muito tempo, mas o número 3 funciona igualmente. Além disso, disown tem uma bandeira nohup de -h, pode rejeitar todos os processos com -a, e pode rejeitar todos os processos em execução com -ar.

Silenciamento é feito por $COMMAND &>/dev/null.

Espero que isto ajude!

9
9
9
2017-05-05 11:55:05 +0000

A resposta mais simples e apenas correcta para bash:

command & disown

Não é necessário separar o processo do terminal, mas sim do invólucro.

9
9
9
2009-03-23 14:55:15 +0000

em tcsh (e talvez em outras conchas também), você pode usar parênteses para destacar o processo.

Compare isto:

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

Com isto:

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

Isto remove a firefox da lista de trabalhos, mas ainda está ligada ao terminal; se você entrou neste nó através de ‘ssh’, tentar sair ainda vai pendurar o processo ssh.

7
7
7
2012-08-07 05:18:25 +0000

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

(comando)&

Quando a saída usada terminal fechado mas o processo ainda está vivo.

verificar -

(sleep 100) & exit

Abrir outro terminal

ps aux | grep sleep

O processo ainda está vivo.

5
5
5
2013-05-22 23:00:56 +0000

Antecedentes e novos conhecimentos de um trabalho é provavelmente uma das primeiras coisas que todos os administradores de sistemas Unix devem saber.

Aqui está como é feito com bash:

./script.sh
# suspend process
{ctrl-Z}
# background process
bg
# list all backgrounded jobs
jobs
# bring it back to foreground
fg
4
4
4
2009-03-23 12:03:50 +0000

Pode executar o seu comando usando o comando nohup, isto separa o seu processo e redirecciona as saídas para um determinado ficheiro… mas não tenho a certeza se é exactamente isso que precisa…

2
2
2
2018-02-05 16:14:17 +0000

Basta adicionar isto no seu bashrc/zshrc:

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

Depois pode executar comandos deserdados como este:

detach gedit ~/.zshrc
2
2
2
2009-03-23 12:10:49 +0000

Experimente daemon – deve estar disponível a partir do seu gestor de pacotes amigável e cuidar exaustivamente de todas as formas de se dissociar do terminal.

1
1
1
2015-06-14 17:53:47 +0000

No meu .bashrc, tenho estas funções precisamente para esse fim:

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

function dos() {
    # run_disowned and silenced

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

Prefixo um comando com dos para o executar desligado do terminal.

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

0
0
0
2010-06-19 16:46:44 +0000

Descobri no Mac OS X que preciso de utilizar tanto o nohup como o disown para garantir que o processo da criança não seja destruído com o terminal.

0
0
0
2014-09-21 04:42:43 +0000

Utilizo o seguinte guião para o fazer. Pára a impressão do processo no terminal, desliga-se com nohup e sai com o estado 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 utilização:

>>> run false
false
Error: false
>>> echo $?
1
>>> run true
true
>>> run sleep 10
sleep 10
>>>
0
0
0
2019-06-21 07:14:46 +0000

sudo apt install ucommon-utils

pdetach command Aqui tem :)

-1
-1
-1
2017-02-15 04:16:48 +0000

Muitas respostas sugeriram a utilização de nohup. Eu preferiria sugerir o uso de pm2 . Usar pm2 sobre nohup tem muitas vantagens, como manter a aplicação viva, manter arquivos de log para a aplicação e muito mais outras características. Para mais detalhes ver isto .

Para instalar pm2 é necessário fazer o download de npm. Para o sistema baseado em Debian

sudo apt-get install npm

e para o Redhat

sudo yum install npm

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

npm install pm2@latest -g

Uma vez terminado pode iniciar a sua aplicação por

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

Para monitorização 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

Gerir processos usando o nome da aplicação ou o id do processo ou gerir todos os processos em conjunto:

$ 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 ficheiros de registo podem ser encontrados em

$HOME/.pm2/logs #contain all applications logs
-1
-1
-1
2017-04-05 13:47:37 +0000

Se o seu objectivo é simplesmente lançar uma aplicação de linha de comando sem manter a janela do terminal, então poderá tentar executar a aplicação depois de lançar o terminal com alt-F2.