Como "corretamente" iniciar um aplicativo a partir de um shell

17

Acho difícil formular a pergunta com precisão, mas darei o meu melhor. Eu uso dwm como meu gerenciador de janelas padrão e dmenu como meu lançador de aplicativos. Eu dificilmente uso aplicativos GUI além do meu navegador. A maior parte do meu trabalho é feita diretamente da linha de comando. Além disso, sou um grande fã do minimalismo em relação a sistemas operacionais, aplicativos, etc. Uma das ferramentas das quais nunca me livrei foi um lançador de aplicativos. Principalmente porque me falta um entendimento preciso de como os lançadores de aplicativos funcionam / o que eles fazem. Mesmo extensa pesquisa na Internet só mostra uma explicação vaga. O que eu quero fazer é se livrar até mesmo do meu lançador de aplicativos, porque além de realmente gerar o aplicativo eu não tenho absolutamente nenhum uso para isso. Para fazer isso, eu realmente gostaria de saber como "corretamente" iniciar os aplicativos do shell. Onde o significado de "corretamente" pode ser aproximado por "como um lançador de aplicativos faria". Eu não afirmo que todos os lançadores de aplicativos funcionam da mesma maneira, porque eu não os entendo bem o suficiente.

Eu conheço as seguintes maneiras de gerar processos a partir do shell:

  1. exec /path/to/Program replace shell com o comando especificado sem criar um novo processo
  2. sh -c /path/to/Program inicia o processo dependente do shell
  3. /path/to/Program inicia o processo dependente do shell
  4. /path/to/Program 2>&1 & processo independente do shell de lançamento
  5. nohup /path/to/Program & inicia o processo independente do shell e redireciona a saída para nohup.out

Atualização 1: posso ilustrar o que dmenu faz a reconstrução de chamadas repetidas para ps -efl sob condições diferentes. Ele gera um novo shell /bin/bash e, como filho desse shell, o aplicativo /path/to/Program . Enquanto a criança estiver por perto, a casca estará por perto. (Como ele gerencia isso está além de mim ...) Em contraste se você emitir nohup /path/to/Program & de um shell /bin/bash , então o programa se tornará o filho desse shell MAS se você sair desse shell, o pai do programa será o processo mais importante . Então, se o primeiro processo foi, e. /sbin/init verbose e tem PPID 1 , então será o pai do programa. Veja o que tentei explicar usando um gráfico: chromium foi lançado por meio de dmenu , firefox foi lançado usando exec firefox & exit :

systemd-+-acpid
        |-bash---chromium-+-chrome-sandbox---chromium-+-chrome-sandbox---nacl_helper
        |                 |                           '-chromium---5*[chromium-+-{Chrome_ChildIOT}]
        |                 |                                                    |-{Compositor}]
        |                 |                                                    |-{HTMLParserThrea}]
        |                 |                                                    |-{OptimizingCompi}]
        |                 |                                                    '-3*[{v8:SweeperThrea}]]
        |                 |-chromium
        |                 |-chromium-+-chromium
        |                 |          |-{Chrome_ChildIOT}
        |                 |          '-{Watchdog}
        |                 |-{AudioThread}
        |                 |-3*[{BrowserBlocking}]
        |                 |-{BrowserWatchdog}
        |                 |-5*[{CachePoolWorker}]
        |                 |-{Chrome_CacheThr}
        |                 |-{Chrome_DBThread}
        |                 |-{Chrome_FileThre}
        |                 |-{Chrome_FileUser}
        |                 |-{Chrome_HistoryT}
        |                 |-{Chrome_IOThread}
        |                 |-{Chrome_ProcessL}
        |                 |-{Chrome_SafeBrow}
        |                 |-{CrShutdownDetec}
        |                 |-{IndexedDB}
        |                 |-{LevelDBEnv}
        |                 |-{NSS SSL ThreadW}
        |                 |-{NetworkChangeNo}
        |                 |-2*[{Proxy resolver}]
        |                 |-{WorkerPool/1201}
        |                 |-{WorkerPool/2059}
        |                 |-{WorkerPool/2579}
        |                 |-{WorkerPool/2590}
        |                 |-{WorkerPool/2592}
        |                 |-{WorkerPool/2608}
        |                 |-{WorkerPool/2973}
        |                 |-{WorkerPool/2974}
        |                 |-{chromium}
        |                 |-{extension_crash}
        |                 |-{gpu-process_cra}
        |                 |-{handle-watcher-}
        |                 |-{inotify_reader}
        |                 |-{ppapi_crash_upl}
        |                 '-{renderer_crash_}
        |-2*[dbus-daemon]
        |-dbus-launch
        |-dhcpcd
        |-firefox-+-4*[{Analysis Helper}]
        |         |-{Cache I/O}
        |         |-{Cache2 I/O}
        |         |-{Cert Verify}
        |         |-3*[{DOM Worker}]
        |         |-{Gecko_IOThread}
        |         |-{HTML5 Parser}
        |         |-{Hang Monitor}
        |         |-{Image Scaler}
        |         |-{JS GC Helper}
        |         |-{JS Watchdog}
        |         |-{Proxy R~olution}
        |         |-{Socket Thread}
        |         |-{Timer}
        |         |-{URL Classifier}
        |         |-{gmain}
        |         |-{localStorage DB}
        |         |-{mozStorage #1}
        |         |-{mozStorage #2}
        |         |-{mozStorage #3}
        |         |-{mozStorage #4}
        |         '-{mozStorage #5}
        |-gpg-agent
        |-login---bash---startx---xinit-+-Xorg.bin-+-xf86-video-inte
        |                               |          '-{Xorg.bin}
        |                               '-dwm-+-dwmstatus
        |                                     '-xterm---bash-+-bash
        |                                                    '-pstree
        |-systemd---(sd-pam)
        |-systemd-journal
        |-systemd-logind
        |-systemd-udevd
        |-wpa_actiond
        '-wpa_supplicant

Atualização 2: Eu acho que a pergunta também pode ser resumida a: Qual deve ser o pai de um processo? Deve por exemplo ser um shell ou deveria ser o processo init , ou seja, o processo com PID 1 ?

    
por lord.garbage 26.08.2014 / 23:42

3 respostas

6

Bem, você parece ter uma boa compreensão disso. Para esclarecer um pouco do que você tem,

  • sh -c /path/to/Program é bastante semelhante a

    $ sh
    % /path/to/Program
    % Ctrl+D                             (or you could type “exit”)
    $ 

    onde você inicia um novo processo de shell, fornecer o caminho do comando do aplicativo para o novo shell, e então deixe o novo shell terminar. Eu mostrei o novo shell dando um prompt diferente para fins de ilustração; isso provavelmente não aconteceria na vida real. A construção sh -c "command" é principalmente útil para fazer coisas complicadas, como agrupar vários comandos em um pacote, então eles se parecem com um único comando (uma espécie de script sem nome de uso único), ou construir comandos complicados, possivelmente a partir de variáveis shell. Você dificilmente usaria isso apenas para executar um único programa com argumentos simples.

  • 2>&1 significa redirecionar o erro padrão para a saída padrão. Isso não tem muito a ver com & ; em vez disso, você usa quando um comando envia mensagens de erro para a tela mesmo se você disser command > file e você deseja capturar as mensagens de erro no arquivo.
  • Redirecionar a saída para nohup.out é um efeito colateral trivial de nohup . O objetivo principal de nohup command & é executar command de forma assíncrona (comumente conhecido como “no fundo”, ou como um "processo independente de shell", para usar suas palavras e configurá-lo para que ele tenha uma chance melhor de poder continuar a executar se você terminar o shell (por exemplo, logout) enquanto o comando ainda estiver em execução.

bash(1) e o Bash Reference Manual são boas fontes de informação.

    
por 27.08.2014 / 00:16
6

Existem algumas formas de executar um programa e desanexá-lo de um terminal. Um deles é executá-lo no plano de fundo de um subshell , como este (substitua firefox pelo seu programa favorito):

(firefox &)

Outra é negar o processo:

firefox & disown firefox

Se você está curioso sobre o funcionamento dos lançadores de aplicativos, dmenu fornece 1 script binário e 2 scripts de shell: dmenu , dmenu_path e dmenu_run , respectivamente.

dmenu_run canaliza a saída de dmenu_path para dmenu, que por sua vez canaliza para qualquer que seja a variável $SHELL definida. Se estiver vazio, usará /bin/sh .

#!/bin/sh
dmenu_path | dmenu "$@" | ${SHELL:-"/bin/sh"} &

dmenu_path é um pouco mais complexo, mas em resumo ele fornece uma lista de binários na variável de ambiente $PATH e usa um cache, se possível.

#!/bin/sh
cachedir=${XDG_CACHE_HOME:-"$HOME/.cache"}
if [ -d "$cachedir" ]; then
        cache=$cachedir/dmenu_run
else
        cache=$HOME/.dmenu_cache # if no xdg dir, fall back to dotfile in ~
fi
IFS=:
if stest -dqr -n "$cache" $PATH; then
        stest -flx $PATH | sort -u | tee "$cache"
else
        cat "$cache"
fi

Não é necessário ter programas em execução em shells. Outra maneira de escrever dmenu_run , sem canalizar em um shell, seria:

#!/bin/sh
$(dmenu_path | dmenu "$@") &
    
por 25.08.2016 / 19:30
4

Eu gosto muito da resposta do G-Man. Mas estou respondendo porque acho que você está confundindo preocupações. Como Wayne ressalta, a melhor resposta é "o que quer que tenha os resultados que você quer".

No gerenciamento de processos do Unix, todo processo tem um pai. A única exceção é o processo init , que é iniciado pelo SO na inicialização. É um comportamento normal de um processo pai levar consigo todos os processos filhos quando morre. Isso é feito enviando o sinal SIGHUP para todos os processos filhos; a manipulação padrão de SIGHUP encerra o processo.

A desova do shell dos processos do usuário não é diferente do que se você codificasse o fork (2) / exec (3) chama no idioma de sua escolha. O shell é seu pai, e se o shell terminar (por exemplo, você faz logoff), então o (s) processo (s) filho (s) que ele (ela) gera (m) vai junto com ele. As nuances que você descreve são apenas formas de modificar esse comportamento.

exec /path/to/program é como chamar exec (3) . Sim, ele substituirá seu shell por program , mantendo qualquer pai que tenha lançado o shell.

sh -c /path/to/program tipo de inutilmente cria um processo de shell filho que criará um processo filho de program . Só é valioso se program for realmente um script que não tenha permissão de execução definida.

/path/to/program cria um processo "em primeiro plano", o que significa que o shell aguarda o processo ser concluído antes de executar qualquer outra ação. No contexto da chamada do sistema, é como fork (2) / exec(3) / waitpid(2) . Observe que o filho herda stdin / stdout / stderr do pai.

/path/to/program & (ignorando o redirecionamento) cria um "processo em segundo plano". O processo ainda é um filho do shell, mas o pai não está esperando que ele termine.

nohup /path/to/program invoca nohup (1) para impedir o envio de SIGHUP para program se o terminal de controle estiver fechado. Quer esteja no primeiro plano ou no plano de fundo, é uma escolha (embora o mais comum seja o processo ser baseado em plano de fundo). Observe que nohup.out é apenas a saída se você não redirecionar o stdout.

Quando você coloca um processo em segundo plano, se o processo pai for interrompido, uma das duas coisas acontecerá. Se o pai for um terminal de controle , então SIGHUP será enviado para as crianças. Se não for, o processo pode ser "órfão" e é herdado pelo processo init .

Quando você redireciona entrada / saída / erro, você está simplesmente conectando os descritores de arquivo que cada processo tem a arquivos diferentes daqueles que ele herda de seu pai. Nada disso afeta a propriedade do processo ou a profundidade da árvore (mas sempre faz sentido redirecionar todos os 3 de um terminal para processos em segundo plano).

Com tudo isso dito, não acho que você deva se preocupar com a criação de processos pelo shell ou sub-shells ou subprocessos, a menos que haja um problema específico que você esteja abordando relacionado ao gerenciamento de processos.

    
por 09.04.2018 / 19:36

Tags