O que um comando "exec" faz?

107

Eu não entendo o comando bash exec. Eu o vi usado dentro de scripts para redirecionar toda a saída para um arquivo (como visto neste ). Mas não entendo como funciona ou o que faz em geral. Eu li as páginas de manual, mas não as entendo.

becko
fonte
Você está familiarizado com o que é um processo ?
fkraiem 18/09/14
1
@fkraiem o que você quer dizer?
Becko
Desculpe, eu quis dizer "o que". : p Mas a resposta parece ser não.
precisa saber é o seguinte
Mas, na verdade, seu script usa execde uma maneira especial, que pode ser explicada de maneira muito mais simples: escreverei uma resposta.
fkraiem 18/09/14
1
Relacionados: unix.stackexchange.com/q/296838/85039
Sergiy Kolodyazhnyy

Respostas:

88

man bash diz:

exec [-cl] [-a name] [command [arguments]]
      If command is specified, it replaces the shell.  No new  process
      is  created.  The arguments become the arguments to command.  If
      the -l option is supplied,  the  shell  places  a  dash  at  the
      beginning  of  the  zeroth  argument passed to command.  This is
      what login(1) does.  The -c option causes command to be executed
      with  an empty environment.  If -a is supplied, the shell passes
      name as the zeroth argument to the executed command.  If command
      cannot  be  executed  for  some  reason, a non-interactive shell
      exits, unless the execfail shell option  is  enabled.   In  that
      case,  it returns failure.  An interactive shell returns failure
      if the file cannot be executed.  If command  is  not  specified,
      any  redirections  take  effect  in  the  current shell, and the
      return status is 0.  If there is a redirection error, the return
      status is 1.

As duas últimas linhas são importantes: se você executar execpor si só, sem um comando, simplesmente fará os redirecionamentos se aplicarem ao shell atual. Você provavelmente sabe que quando executa command > file, a saída de commandé gravada em filevez de no seu terminal (isso é chamado de redirecionamento ). Se você executar exec > file, o redirecionamento se aplicará a todo o shell: qualquer saída produzida pelo shell é gravada no filelugar do terminal. Por exemplo aqui

bash-3.2$ bash
bash-3.2$ exec > file
bash-3.2$ date
bash-3.2$ exit
bash-3.2$ cat file
Thu 18 Sep 2014 23:56:25 CEST

Primeiro inicio um novo bashshell. Então, neste novo shell, eu corro exec > file, para que toda a saída seja redirecionada para file. De fato, depois disso, eu corro, datemas não recebo saída, porque a saída é redirecionada para file. Então saio do shell (para que o redirecionamento não se aplique mais) e vejo que, de filefato, contém a saída do datecomando que executei anteriormente.

Fkraiem
fonte
42
Esta é apenas uma explicação parcial. execserve para substituir também o processo atual do shell por um comando, para que o pai siga um caminho e o filho seja dono do pid. Isso não é apenas para redirecionamento. Por favor, adicione esta informação
Sergiy Kolodyazhnyy
3
Seguindo o comentário de @ SergiyKolodyazhnyy, o exemplo que acabei de encontrar que me levou a esta página é um docker-entrypoint.sh, onde, após executar várias ações na configuração do nginx, a linha final do script é exec nginx <various nginx arguments>. Isso significa que o nginx assume o controle do script bash e agora o nginx é o principal processo de execução do contêiner, não o script. Presumo que isso seja apenas para limpeza, a menos que alguém saiba uma razão mais concreta para isso?
21418 Luke Griffiths
1
@ Lucas Isso é chamado de "script de wrapper". Também é exemplo disso gnome-terminal, que pelo menos em 14.04 tinha um script de wrapper para configurar argumentos. E esse é o único objetivo, realmente - definir artes e ambiente. Outro caso seria limpar - matar a instância anterior de um processo primeiro e lançar um novo
Sergiy Kolodyazhnyy 21/11
outro execexemplo semelhante ao nginxexemplo dado por @LukeGriffiths é o ~/.vnc/xstartupscript que vncserverusa para configurar um processo de servidor VNC e, em seguida, exec gnome-sessionou exec startkdee assim por diante.
Trevor Boyd Smith
@LukeGriffiths, o principal motivo para execum script de inicialização de contêiner é que o PID 1, o ENTRYPOINT do contêiner, tem um significado especial no Docker. É um processo principal que recebe sinais e, quando existe, o contêiner também sai. execapenas uma maneira de remover shessa cadeia de comando e tornar o daemon o principal processo do contêiner.
kkm
45

exec é um comando com dois comportamentos muito distintos, dependendo se pelo menos um argumento é usado com ele ou se nenhum argumento é usado.

  • Se pelo menos um argumento for passado, o primeiro será usado como um nome de comando e exectentará executá-lo como um comando passando os argumentos restantes, se houver, para esse comando e gerenciando os redirecionamentos, se houver.

  • Se o comando transmitido como primeiro argumento não existir, o shell atual, não apenas o comando exec, sai por engano.

  • Se o comando existe e é executável, ele substitui o shell atual. Isso significa que, se execaparecer em um script, as instruções após a chamada exec nunca serão executadas (a menos que execesteja em um subshell). execnunca retorna. As armadilhas do shell como "EXIT" também não serão acionadas.

  • Se nenhum argumento for passado, execserá usado apenas para redefinir os descritores atuais do arquivo shell. O shell continua após o exec, ao contrário do caso anterior, mas a entrada, saída, erro ou qualquer outro descritor de arquivo padrão foi redirecionado.

  • Se alguns dos redirecionamentos forem usados /dev/null, qualquer entrada dele retornará EOF e qualquer saída será descartada.

  • Você pode fechar os descritores de arquivos usando -como origem ou destino, por exemplo exec <&-. A leitura ou gravação subsequente falhará.

Aqui estão dois exemplos:

echo foo > /tmp/bar
exec < /tmp/bar # exec has no arguments, will only affect current shell descriptors, here stdin
cat # simple command that read stdin and write it to stdout

Este script produzirá "foo" como o comando cat, em vez de aguardar a entrada do usuário, como faria no caso usual, receberá sua entrada do arquivo / tmp / bar que contém foo.

echo foo > /tmp/bar
exec wc -c < /tmp/bar # exec has two arguments, the control flow will switch to the wc command
cat

Este script será exibido 4(o número de bytes em / tmp / bar) e será encerrado imediatamente. O catcomando não será executado.

jlliagre
fonte
4
`Algumas postagens antigas nunca envelhecem ... +1.
Cbhihe
3
Se alguns dos redirecionamentos usarem / dev / null, o descritor de arquivo associado será fechado. Não, ele realmente redireciona para / de /dev/null, portanto, as gravações ainda são bem-sucedidas e as leituras retornam EOF. close(2)em um fd faria com que as chamadas do sistema de leitura / gravação retornassem erros, e você faz isso exec 2>&-por exemplo.
Peter Cordes
2
Tente você mesmo:: exec 3</dev/null; ls -l /proc/self/fdobserve que o fd 3 será aberto somente para leitura em / dev / null. Em seguida, feche-o novamente com exec 3<&-e você poderá ver (com ls -l /proc/$$/fdnovamente) que seu processo de shell não tem mais fd 3. (fechar stdin com exec <&-pode ser útil em scripts, mas de forma interativa, é um logout.)
Peter Cordes
@ PeterCordes Você está absolutamente certo. Resposta atualizada. Obrigado!
Jlliagre 7/07
1
Essa resposta é ótima porque explica que os dois casos de uso da execresposta mais votada atualmente falam apenas sobre um caso de uso e a outra resposta de g_p fala apenas sobre o outro caso de uso. E essa resposta é boa e concisa / legível para um assunto tão complexo.
Trevor Boyd Smith
33

Para entender execvocê precisa primeiro entender fork. Eu estou tentando mantê-lo curto.

  • Quando você chega a uma bifurcação na estrada, geralmente tem duas opções. Os programas Linux alcançam essa bifurcação quando atendem a uma fork()chamada do sistema.

  • Programas normais são comandos do sistema que existem em um formulário compilado no seu sistema. Quando esse programa é executado, um novo processo é criado. Esse processo filho tem o mesmo ambiente que seu pai, apenas o número de identificação do processo é diferente. Este procedimento é chamado de bifurcação .

  • A bifurcação fornece uma maneira para um processo existente iniciar um novo. No entanto, pode haver situações em que um processo filho não faz parte do mesmo programa que o processo pai. Neste caso execé usado. exec substituirá o conteúdo do processo atualmente em execução pelas informações de um programa binário.
  • Após o processo de bifurcação, o espaço de endereço do processo filho é substituído pelos novos dados do processo. Isso é feito através de uma chamada executiva ao sistema.
g_p
fonte
3
você pode explicar por que execpode redirecionar uma saída de script, como no link que eu postei?
Becko
1
Achei isso pouco claras "No entanto, pode haver situações em que um processo filho não é a parte do mesmo programa como processo pai"
cdosborn
6

Em bash, se você fizer help exec:

$ help exec
exec: exec [-cl] [-a name] [command [arguments ...]] [redirection ...]
    Replace the shell with the given command.

    Execute COMMAND, replacing this shell with the specified program.
    ARGUMENTS become the arguments to COMMAND.  If COMMAND is not specified,
    any redirections take effect in the current shell.

    Options:
      -a name   pass NAME as the zeroth argument to COMMAND
      -c        execute COMMAND with an empty environment
      -l        place a dash in the zeroth argument to COMMAND

    If the command cannot be executed, a non-interactive shell exits, unless
    the shell option `execfail' is set.

    Exit Status:
    Returns success unless COMMAND is not found or a redirection error occurs.

O bit relevante:

If COMMAND is not specified, any redirections take effect in the current shell.

execé um shell embutido , que é o equivalente do shell da execfamília de chamadas de sistema das quais o G_P fala (e cujas páginas de manual você parece ter lido). Ele apenas possui a funcionalidade mandatada pelo POSIX de afetar o shell atual se nenhum comando for especificado.

muru
fonte