Eu defini uma função shell (vamos chamá-lo clock
), que eu quero usar como invólucro para outro comando, semelhante à time
função, por exemplo clock ls -R
.
Minha função shell executa algumas tarefas e termina com exec "$@"
.
Eu gostaria que essa função funcionasse mesmo com os shell embutidos, por exemplo, clock time ls -R
deve gerar o resultado do time
embutido, e não do /usr/bin/time
executável. Mas exec
sempre acaba executando o comando.
Como posso fazer com que minha função Bash funcione como um invólucro que também aceite argumentos internos do shell?
Edit : Acabei de saber que time
não é um Bash embutido, mas uma palavra reservada especial relacionada a pipelines. Ainda estou interessado em uma solução para embutidos, mesmo que não funcione time
, mas uma solução mais geral seria ainda melhor.
fonte
exec bash -c \' "$@" \'
. A menos que seu comando no primeiro parâmetro seja reconhecido como um script de shell, ele será interpretado como um binário para ser executado diretamente. Alternativamente, e de forma mais simples, apenas perca aexec
chamada e"@"
do seu shell original.Respostas:
Você definiu uma função bash. Então você já está em um shell bash ao invocar essa função. Portanto, essa função poderia simplesmente se parecer com:
Essa função pode ser chamada com bash builtins, palavras reservadas especiais, comandos e outras funções definidas:
Um apelido:
Um bash embutido:
Outra função:
Um executável:
fonte
$@
eexec $@
, se eu sei que estou executando um comando real?exec
, o comando substitui o shell. Portanto, não há mais builtins, aliases, palavras reservadas especiais, palavras definidas, porque o executável é executado via chamada do sistemaexecve()
. Esse syscall espera um arquivo executável.exec $0
um único processo, enquanto$@
ainda há dois.$@
possui o shell em execução como pai e o comando como processo filho. Mas quando você quiser usar builtins, aliases e assim por diante, precisará preservar o shell. Ou comece um novo.A única maneira de iniciar um shell embutido ou uma palavra-chave do shell é iniciar um novo shell, porque o exec "substitui o shell pelo comando especificado". Você deve substituir sua última linha por:
Isso funciona com palavras internas e reservadas; O princípio é o mesmo.
fonte
Se o wrapper precisar inserir código antes do comando fornecido, um alias funcionará à medida que forem expandidos em um estágio muito inicial:
Os aliases são quase literalmente inseridos no lugar da palavra com alias, portanto, o final
;
é importante - ele faz aclock time foo
expansão parado this; do that; time foo
.Você pode abusar disso para criar aliases mágicos que ignoram as aspas.
Para inserir código após um comando, você pode usar o gancho "DEBUG".
Especificamente:
O gancho ainda é executado antes do comando, mas, ao retornar,
false
ele diz ao bash para cancelar a execução (porque o gancho já o executou via eval).Como outro exemplo, você pode usar isso como alias
command please
parasudo command
:fonte
A única solução que eu poderia encontrar até agora seria realizar uma análise de caso para distinguir se o primeiro argumento é um comando, interno ou palavra-chave e falhar no último caso:
No
time
entanto, ele não funciona , portanto pode haver uma solução melhor (e mais concisa).fonte