Exemplo de caso de uso / prático para o exec incorporado do Bash

Respostas:

18

execé frequentemente usado em scripts de shell que atuam principalmente como wrappers para iniciar outros binários. Por exemplo:

#!/bin/sh

if stuff;
    EXTRA_OPTIONS="-x -y -z"
else
    EXTRA_OPTIONS="-a foo"
fi

exec /usr/local/bin/the.real.binary $EXTRA_OPTIONS "$@"

para que, após a conclusão da execução do wrapper, o binário "real" assuma o controle e não haja mais nenhum rastreamento do script do wrapper que ocupou temporariamente o mesmo slot na tabela de processos. O binário "real" é um filho direto de tudo o que o lançou, em vez de um neto.

Você também mencionou o redirecionamento de E / S na sua pergunta. Esse é um caso de uso bem diferente exece não tem nada a ver com a substituição do shell por outro processo. Quando execnão tem argumentos, assim:

exec 3>>/tmp/logfile

os redirecionamentos de E / S na linha de comando entram em vigor no processo atual do shell, mas o processo atual do shell continua em execução e passa para o próximo comando no script.

Celada
fonte
1
Você pode dizer que os dois casos estão relacionados em que, para ambos, execdiz ao shell para não executar a ação (executar um comando ou executar um redirecionamento) em um processo filho, mas no mesmo processo.
Stéphane Chazelas
5

Eu usei um shell execembutido para obter um ID do processo (PID) para um programa Java. Pode haver uma maneira de obter o PID de dentro do Java agora, mas há vários anos, não havia. Depois que um processo possui seu próprio PID, ele pode gravá-lo em um arquivo PID (procure /var/run/nomes de arquivos com o sufixo '.pid') para permitir que os programas de gerenciamento saibam o PID do processo em execução e para impedir uma segunda instância do mesmo servidor em execução. Funciona mais ou menos assim:

exec java -cp=YourServer.jar StartClass -p $$

O código no main()método da classe StartClassmanipula a análise de argumentos e pode encontrar seu próprio ID do processo.

Bruce Ediger
fonte
2

Por diversão, execute o seguinte programa (traduzido para o idioma de sua escolha) em segundo plano em um sistema com contabilidade e limites de processo do usuário.

while(true) fork();

Agora que todos os slots na tabela de processos que você tem permissão para usar estão cheios de cópias desse programa em execução, como pretende eliminá-lo? O lançamento do kill (1) requer outro slot de processo, que você não pode ter. Certamente seria útil fazer com que o shell se substituísse pelo comando kill ...

exec /bin/kill -9 -1

(Supõe que seu sistema tenha kill (1) em / bin / kill. "Exec`, que mata` -9 -1 "é potencialmente mais seguro.) Isso envia o SIGKILL para todos os processos que você puder.

(Nota: Não efetue logout no shell de inicialização, a menos que os limites do processo sempre permitam um novo login em um slot de processo para o shell. Isso pode ser um pouco mais difícil de limpar se você o fizer. Certamente não fiz isso no início dos anos 90. Não.)

Eric Towers
fonte
3
(1) Essa resposta seria um pouco melhor se você realmente mostrasse o execcomando que seria útil nessa situação. (2) Essa resposta é um pouco arcaica; o killcomando é um comando embutido no bash há muitos anos, em grande parte por causa dessa preocupação.
G-Man diz 'Reinstate Monica'
@ G-Man: Você entende que seu item (2) faz dessa resposta uma resposta precisa ao OP?
Eric Towers
Não, eu não entendo isso. Por favor, explique para mim.
G-Man diz 'Restabelecer Monica'
4
Eu não estou seguindo você. A pergunta não pede exemplos práticos de todos os comandos do bash builtin; ele pede exemplos de exec- e o fato de killser um builtin não tem realmente nada a ver com o execbuiltin.
G-Man diz 'Reinstate Monica'
1
Acabei de ler sua atualização para sua resposta. (1) Adivinha o quê? Se a tabela de processos estiver cheia, a substituição de comandos (por exemplo, `which kill`) também não funcionará. (2) BTW, o $(…)formulário é recomendado sobre o `…`formulário. (3) Mas não há nada perigoso em adivinhar o diretório. Se você digitar acidentalmente exec /binn/kill, você receberá uma mensagem de erro e seu shell não desaparecerá. (4) Mas você nem precisa se preocupar com qual diretório o kill.  execUsa $PATH, assim como os comandos normais, assim exec kill …funciona (supondo que você tenha /binno seu caminho de pesquisa).
G-Man diz 'Restabelecer Monica'
1
  • Isso é semelhante ao exemplo de Bruce de precisar conhecer o PID de um processo:

    (cmdpid = $ BASHPID; (dorme 300; mate "$ cmdpid") & comando de execução longa )

    em que você

    1. Inicie um subshell (o externo (e )),
    2. Descubra o PID do subshell. ( $$fornecerá o PID do shell principal.)
    3. Desanexe um subconjunto que encerre seu processo após um tempo limite e
    4. Execute um comando no processo do subshell que você criou na etapa 1.

    Isso será executado long-running-command, mas apenas por um período de tempo limitado predeterminado. 

  • Isso é um pouco frívolo, mas, se você decidir ser root (ou algum outro usuário) pelo resto da sua sessão de login, poderá exec su.

    Na verdade, posso imaginar um cenário em que isso seria realmente útil. Suponha que você esteja conectado a um sistema remoto e, por algum motivo, haja um problema ao interromper a conexão e iniciar uma nova conexão. Por exemplo, suponha que o sistema remoto tenha um firewall que siga um cronograma. Você teve permissão para se conectar quando o fez e as conexões estabelecidas não são fechadas, mas, no momento, novas conexões não estão sendo aceitas.

    Você fez o que queria e está pronto para sair. Seu amigo Bob está na sala com você e ele quer fazer algum trabalho no sistema remoto - mas ele não poderá se conectar. Então, você digita exec su - bobe, quando o prompt da senha aparecer, entregue a estação de trabalho para ele. Agora não há nenhum processo com o seu UID (a menos que você tenha executado algo em segundo plano), então Bob não poderá mexer nos seus arquivos. Ele efetivamente assumiu sua conexão (com seu consentimento e cooperação).

    Notas:

    • Claro que isso não funcionará se você não tiver permissão para executar su.
    • Ele será registrado, portanto, talvez você precise explicar seus motivos a alguém. Como você está contornando a política (a programação do firewall), pode ter problemas.
    • Não garanto que seja 100% seguro. Por exemplo, whoprovavelmente ainda mostrará seu nome. É concebível que algum programa (mal escrito) use isso para pensar que Bob é você e dar a ele acesso aos seus recursos.
    • Se o sistema fizer auditoria, as ações de Bob poderão ser auditadas em seu nome.
G-Man diz que 'restabelece Monica'
fonte
Observe que, na prática, na maioria dos shells, (a;b)já é o mesmo (a;exec b)que os shells otimizam o garfo para o último comando em um subshell. As únicas exceções parecem ser bashe mksh. Usar execajuda para garantir isso.
Stéphane Chazelas