exec comando bin bash

3

Eu estava verificando um script de shell e notei o comando abaixo - exec. o comando exec executa o cmdline, mas eu estou querendo saber o que o comando :-/bin/bash faz aqui.

cmdline="$@"
    exec ${cmdline:-/bin/bash}
    
por user1050619 20.10.2017 / 21:13

1 resposta

2

Como o código funciona e por que

Existem 3 coisas principais acontecendo aqui:

  • $@ é uma variável de shell especial que se expande para todos os argumentos de linha de comando para o script
  • ${cmdline:-/bin/bash} é uma das estruturas de expansão de parâmetros; se a variável cmdline não estiver definida ou vazia, toda a porção ${} será substituída pelo que vier depois de - sign, neste caso /bin/bash ; isso é uma espécie de abreviação para if ou operador ternário em outras linguagens de programação (não exatamente, mas bom o suficiente para comparação)
  • exec é usado para gerar um processo que ultrapassará o PID do processo atual, ou seja, simplesmente substitua seu processo de script pelo que estiver dentro desse ${}

Juntando tudo isso, o código simplesmente pega os argumentos da linha de comando e os executa, e se não houver argumentos de linha de comando para o script - você obtém bash shell interativo. Observe que você também pode passar opções para exec mencionadas na documentação - compare ./exec_script.sh -c env e ./exec_script.sh env .

Bom na teoria, ruim na prática

A abordagem em si pode parecer complicada, mas é comum ver essa abordagem com exec em scripts de wrapper - um script configura o ambiente e verifica as variáveis antes de organizar tudo para executar o comando real. A diferença aqui é que no comando wrapper scripts o comando está configurado - um script wrapper geralmente configura ambiente e argumentos para executar apenas um programa em particular.

Por outro lado, este script tem como objetivo executar o que o usuário coloca na linha de comando. E isso tem um problema por causa de como o shell funciona - dado os argumentos da linha de comando que contêm caracteres especiais, o comando que você pretende executar pode pausa. Aqui está o que eu quero dizer:

# This is how it's supposed to work
$ printf 'one%stwo' $'\t'                                                              
one     two

# This is how it works with unquoted parameter expansion
$ ./exec_script.sh  printf 'one%stwo' $'\t'                                            
onetwo

Imagine se você está tentando usar esse script para executar my_cool_command filename$'\t'with$'\t'tabs.txt ; na melhor das hipóteses - quebra de comandos, mas se você também tem filenamewithtab.txt arquivo na sua pasta atual, my_cool_command irá operar em arquivo completamente errado. E citar a expansão dos parâmetros também não ajuda, porque então ele quebra:

$ ./exec_script.sh  printf 'one%stwo' $'\t'                                            
./exec_script.sh: line 4: exec: printf one%stwo     : not found

Documentação relevante

Aqui está a parte relevante sobre a expansão de parâmetro do manual bash (versão 4.3):

  

$ {parameter: -word}

     

Usar valores padrão. Se o parâmetro não for definido ou nulo, a expansão da palavra será substituída. Caso contrário, o valor do parâmetro é substituído.

seção "Parâmetros especiais":

  

@ Expande para os parâmetros posicionais, começando de um. Quando a expansão ocorre entre aspas duplas, cada parâmetro se expande para uma palavra separada. Isto é, "$ @" é equivalente a "$ 1" "$ 2" ... Se a expansão de aspas duplas ocorrer dentro de uma palavra, a expansão do primeiro parâmetro é unida à parte inicial da palavra original e a expansão do último parâmetro é unido com a última parte da palavra original. Quando não há parâmetros posicionais, "$ @" e $ @ se expandem para nada (ou seja, são removidos).

Na seção "Comandos internos do Shell":

  

exec [-cl] [-a nome] [comando [argumentos]]

     

Se o comando for especificado, ele substituirá o shell. Nenhum novo processo é criado. Os argumentos se tornam os argumentos para comandar. Se a opção -l for fornecida, o shell colocará um traço no início do argumento zeroth passado para o comando. Isto é o que o login (1) faz. A opção -c faz com que o comando seja executado com um ambiente vazio. Se -a é fornecido, o shell passa o nome como o argumento zeroth para o comando executado. Se o comando não puder ser executado por algum motivo, um shell não interativo será encerrado, a menos que a opção do shell execfail esteja ativada. Nesse caso, ele retorna falha. Um shell interativo retorna falha se o arquivo não puder ser executado. Se o comando não for especificado, qualquer redirecionamento terá efeito no shell atual e o status de retorno será 0. Se houver um erro de redirecionamento, o status de retorno será 1.

Conclusão e pensamentos

Esse script em si tem uma boa ideia na teoria, mas é ruim na prática. O comando exec funcionará bem em scripts de wrapper e, de fato, como um dos principais usuários do Unix & amp; Site Linux, Gilles , mencionado "... exec também economiza um pouco de memória (e outros recursos como PIDs etc) desde que não há necessidade de manter um shell extra com nada para fazer ". Mas o script neste caso visa reinventar a roda e fazer o que a shell já faz bem o suficiente - ou seja, executar comandos com argumentos.

    
por Sergiy Kolodyazhnyy 20.10.2017 / 21:23