Consulte BashFAQ # 105 sobre: porque set -eé considerado muito mais sujeito a erros do que o tratamento de erros escrito à mão. (Se estiver com pressa, pule a analogia no topo para os exercícios abaixo).
Charles Duffy
Respostas:
71
Basicamente, ele pega quaisquer argumentos de linha de comando passados entrypoint.she os executa como um comando. A intenção é basicamente "Faça tudo neste script .sh, então no mesmo shell execute o comando que o usuário passa na linha de comando".
Observe também que exec "$@"isso substituirá o processo em execução pelo novo processo gerado para os argumentos passados. Importante para a sinalização do Docker: stackoverflow.com/a/32261019/99717
Hawkeye Parker
35
set -edefine uma opção do shell para sair imediatamente se qualquer comando executado sair com um código de saída diferente de zero. O script retornará com o código de saída do comando com falha. Na página de manual do bash:
conjunto -e:
Saia imediatamente se um pipeline (que pode consistir em um único comando simples), uma lista ou um comando composto (consulte SHELL GRAMMAR acima), sair com um status diferente de zero. O shell não fecha se o comando que falha fizer parte da lista de comandos imediatamente após a palavra-chave while ou until, parte do teste após as palavras reservadas if ou elif, parte de qualquer comando executado em um && ou || list, exceto o comando após o && ou || final, qualquer comando em um pipeline exceto o último, ou se o valor de retorno do comando estiver sendo invertido com!. Se um comando composto diferente de um subshell retornar um status diferente de zero porque um comando falhou enquanto -e estava sendo ignorado, o shell não sai. Um trap em ERR, se definido, é executado antes que o shell saia.
Se um comando composto ou função shell é executado em um contexto onde -e está sendo ignorado, nenhum dos comandos executados dentro do comando composto ou corpo da função será afetado pela configuração -e, mesmo se -e for definido e um comando retornar um status de falha. Se um comando composto ou função shell definir -e durante a execução em um contexto onde -e for ignorado, essa configuração não terá nenhum efeito até que o comando composto ou o comando que contém a chamada de função seja concluído.
exec "$@"é normalmente usado para fazer do ponto de entrada uma passagem que executa o comando docker. Ele irá substituir o shell em execução atual pelo comando que "$@"está apontando para. Por padrão, essa variável aponta para os argumentos da linha de comando.
Se você tiver uma imagem com um entrypoint apontando para entrypoint.sh e executar seu contêiner como docker run my_image server start, isso se traduzirá em execução entrypoint.sh server startno contêiner. Na linha exec entrypoint.sh, o shell em execução como pid 1 se substituirá pelo comando server start.
Isso é crítico para o tratamento do sinal. Sem usar exec, o server startno exemplo acima seria executado como outro pid e, depois de sair, você retornaria ao seu script de shell. Com um shell em pid 1, um SIGTERM será ignorado por padrão. Isso significa que o sinal de parada normal que docker stopenvia para o seu contêiner nunca seria recebido pelo serverprocesso. Após 10 segundos (por padrão), docker stopdesistiria do desligamento normal e enviaria um SIGKILL que forçará seu aplicativo a sair, mas com possível perda de dados ou conexões de rede fechadas, que os desenvolvedores de aplicativos poderiam ter codificado se tivessem recebido o sinal. Isso também significa que seu contêiner sempre levará 10 segundos para parar.
Observe que com comandos de shell como shifte set --, você pode alterar o valor de "$@". Por exemplo, aqui está uma pequena parte de um script que remove o /bin/sh -c "..."do comando que pode aparecer se você usar a sintaxe do shell do docker para CMD:
Veja a testespecificação POSIX , que marca -aobsoleta. [ "$#" -gt 1 ] && [ "$1" = /bin/sh ]é a substituição correta (não há necessidade de x"$1"hackery ao usar apenas a sintaxe não obsoleta).
Charles Duffy
Além disso, shift 2; set -- $1não é o mesmo que evalanalisar a string. Considere /bin/sh -c 'printf "%s\n" "hello world" "goodbye world"', se você deseja um caso de teste concreto, e veja que o Bash não analisa aspas ao converter uma string em argumentos .
Charles Duffy
@CharlesDuffy obrigado pela dica sobre a opção obsoleta, tenho certeza que cometerei esse erro novamente, velhos hábitos são difíceis de morrer. Com o eval, acredito que ainda quero espelhar o comportamento de /bin/sh -cteria na string, mas, por favor, me diga se estou faltando alguma coisa.
BMitch
30
set -e - saia do script se algum comando falhar (valor diferente de zero)
exec "$@"- redirecionará variáveis de entrada, veja mais aqui
"Irá redirecionar as variáveis de entrada"? Eh? execcertamente tem um modo de uso em que está realizando redirecionamentos, mas este não é esse modo.
set -e
é considerado muito mais sujeito a erros do que o tratamento de erros escrito à mão. (Se estiver com pressa, pule a analogia no topo para os exercícios abaixo).Respostas:
Basicamente, ele pega quaisquer argumentos de linha de comando passados
entrypoint.sh
e os executa como um comando. A intenção é basicamente "Faça tudo neste script .sh, então no mesmo shell execute o comando que o usuário passa na linha de comando".Vejo:
fonte
exec "$@"
isso substituirá o processo em execução pelo novo processo gerado para os argumentos passados. Importante para a sinalização do Docker: stackoverflow.com/a/32261019/99717set -e
define uma opção do shell para sair imediatamente se qualquer comando executado sair com um código de saída diferente de zero. O script retornará com o código de saída do comando com falha. Na página de manual do bash:exec "$@"
é normalmente usado para fazer do ponto de entrada uma passagem que executa o comando docker. Ele irá substituir o shell em execução atual pelo comando que"$@"
está apontando para. Por padrão, essa variável aponta para os argumentos da linha de comando.Se você tiver uma imagem com um entrypoint apontando para entrypoint.sh e executar seu contêiner como
docker run my_image server start
, isso se traduzirá em execuçãoentrypoint.sh server start
no contêiner. Na linha execentrypoint.sh
, o shell em execução como pid 1 se substituirá pelo comandoserver start
.Isso é crítico para o tratamento do sinal. Sem usar
exec
, oserver start
no exemplo acima seria executado como outro pid e, depois de sair, você retornaria ao seu script de shell. Com um shell em pid 1, um SIGTERM será ignorado por padrão. Isso significa que o sinal de parada normal quedocker stop
envia para o seu contêiner nunca seria recebido peloserver
processo. Após 10 segundos (por padrão),docker stop
desistiria do desligamento normal e enviaria um SIGKILL que forçará seu aplicativo a sair, mas com possível perda de dados ou conexões de rede fechadas, que os desenvolvedores de aplicativos poderiam ter codificado se tivessem recebido o sinal. Isso também significa que seu contêiner sempre levará 10 segundos para parar.Observe que com comandos de shell como
shift
eset --
, você pode alterar o valor de"$@"
. Por exemplo, aqui está uma pequena parte de um script que remove o/bin/sh -c "..."
do comando que pode aparecer se você usar a sintaxe do shell do docker paraCMD
:# convert `/bin/sh -c "server start"` to `server start` if [ $# -gt 1 ] && [ x"$1" = x"/bin/sh" ] && [ x"$2" = x"-c" ]; then shift 2 eval "set -- $1" fi .... exec "$@"
fonte
test
especificação POSIX , que marca-a
obsoleta.[ "$#" -gt 1 ] && [ "$1" = /bin/sh ]
é a substituição correta (não há necessidade dex"$1"
hackery ao usar apenas a sintaxe não obsoleta).shift 2; set -- $1
não é o mesmo queeval
analisar a string. Considere/bin/sh -c 'printf "%s\n" "hello world" "goodbye world"'
, se você deseja um caso de teste concreto, e veja que o Bash não analisa aspas ao converter uma string em argumentos .eval
, acredito que ainda quero espelhar o comportamento de/bin/sh -c
teria na string, mas, por favor, me diga se estou faltando alguma coisa.set -e
- saia do script se algum comando falhar (valor diferente de zero)exec "$@"
- redirecionará variáveis de entrada, veja mais aquifonte
exec
certamente tem um modo de uso em que está realizando redirecionamentos, mas este não é esse modo.