O exec deve sempre ser a última linha do shell script?

0

Eu tenho um script de shell que faz o seguinte:

export FOO=foo           # step 1
/usr/bin/java my-server  # step 2

Este script de shell é iniciado por um programa pai que precisa conhecer o PID do processo iniciado na Etapa 2. Isso é feito atualmente executando exec no comando de início do servidor para substituir o shell pelo comando na Etapa 2. Assim, o PID do processo que executa o script torna-se o PID do processo “meu servidor”.

Agora tenho que adicionar outro comando a esse script de shell que valida rapidamente o servidor iniciado na Etapa 2. Assim, meu programa agora deve ter a seguinte aparência:

export FOO=foo                      # step 1
exec /usr/bin/java my-server &      # step 2
/usr/bin/java my-validation         # step 3

Posso adicionar o Passo 3 como mostrado acima? Quais são as alternativas para essa abordagem?

    
por prgrmmr 17.08.2018 / 21:59

2 respostas

2

Para combinar o que a outra resposta e os comentários disseram, adicione um pouco:

  • exec your_command & não faz sentido. A linha de comando será executada em um subshell assíncrono, e o exec será essencialmente ignorado.
    • Isso é uma simplificação ligeira . Se dissermos
      (command1; command2) &
      então command1 e command2 será executado ( command2 após command1 conclui) em um subshell assíncrono. Mas se nós diga
      (exec command1; command2) &
      então command1 será executado mas command2 não.
  • Qualquer coisa depois de uma forma correta O comando exec (que não consiste apenas em redirecionamentos) em um script será ignorado. Mesmo se o exec falhar, o shell sairá sem executar as linhas subseqüentes (pode-se usar a opção command exec ... ou bash execfail para impedir que exec saia do shell após a falha).
  • se o exec for executado em um subshell, como em exec cmd & ou exec cmd | cmd2 ou (exec cmd3) , apenas essa sub-ssh sairá.
  • Se o seu comando de validação precisar conhecer o PID do processo do servidor, você pode estar sem sorte.
  • Caso contrário, se o seu comando de validação espera automaticamente um tempo para o servidor iniciar, você pode fazer

    export FOO=foo                      # step 1
    /usr/bin/java my-validation &       # step 1½
    exec /usr/bin/java my-server        # step 2
    
  • Caso contrário, você pode fazer

    export FOO=foo                              # step 1
    (sleep 10; /usr/bin/java my-validation) &   # step 1½
    exec /usr/bin/java my-server                # step 2
    

    Aviso: se o processo do "meu servidor" terminar rapidamente, então é bem possível que o seu script saia, e o processo pai recuperará o controle e retomará a execução, antes que o seu comando “my-validation” seja executado. Se o processo pai e o comando “my-validation” ambos escrevem a saída para o mesmo local, eles podem ser misturados.

    Mas se o processo pai não estiver esperando o script sair, isso pode não ser um problema.

por 20.08.2018 / 07:22
1

exec program substitui o processo do script pelo novo program , portanto, deve ser usado somente quando isso fizer sentido. Ou seja, o script atual desaparece e não poderá executar comandos subsequentes (a menos que exec program falhe).

exec program como a última linha de um script de shell é útil onde program é executado por longos períodos de tempo e você não deseja que um processo de shell inútil permaneça na árvore de processos até que program seja encerrado. Use pstree ou outras ferramentas de processo para inspecionar a diferença entre:

#!/bin/sh
echo $$
sleep 9999

e

#!/bin/sh
echo $$
exec sleep 9999

exec program não é de todo útil se você deseja executar outros comandos shell após o exec , pois os comandos shell não são atingidos (a menos que exec falhe).

Validar algo após o lançamento é realmente complicado, pois /usr/bin/java my-server demorará a ser lançado (e o Java pode ser extremamente lento nesse sentido; lembro-me de um processo Java que levou mais de 45 segundos para ficar disponível ou se fechar down ...) e dependendo de quão ocupado o sistema é ou o agendador, o processo de validação pode ser executado antes ou depois da execução do my-server . Como um kluge você pode atrasar a etapa de validação com algo como

export FOO=foo
/usr/bin/java my-server &
sleep 10
exec /usr/bin/java my-validation

que dá 10 segundos para o my-server se lançar, o que pode ou não ser suficiente dependendo de quão ocupado o sistema está e por quanto tempo my-server demora para iniciar. Novamente, vi processos Java levarem mais de 45 segundos para serem iniciados, e isso não estava em um sistema ocupado em que o tempo de inicialização poderia ser ainda maior. O sleep pode não ser necessário se my-validation for inteligente o suficiente para esperar que my-server comece a funcionar.

Pode fazer mais sentido apenas iniciar o servidor:

#!/bin/sh
export FOO=foo
exec /usr/bin/java my-server

e faça a validação de que o serviço está sendo executado por meio de uma estrutura de monitoramento , em outro lugar.

Ainda outra abordagem seria integrar com systemd ou algum outro framework de init moderno que oferece melhor controle de processo do que um script de shell faz. Por exemplo, um processo pode se comunicar com systemd se foi iniciado corretamente ou systemd pode reiniciar automaticamente o serviço sob várias condições, e assim por diante.

    
por 18.08.2018 / 16:59