Para encurtar a história: eu gostaria de acompanhar o modo como alguns executáveis são chamados para rastrear algum comportamento do sistema. Digamos que eu tenho um executável:
/usr/bin/do_stuff
E na verdade é chamado por vários nomes diferentes via link simbólico:
/usr/bin/make_tea -> /usr/bin/do_stuff
/usr/bin/make_coffee -> /usr/bin/do_stuff
e assim por diante. Claramente, do_stuff
usaremos o primeiro argumento recebido para determinar qual ação é realmente executada, e o restante dos argumentos será tratado à luz disso.
Gostaria de gravar sempre chamadas para /usr/bin/do_stuff
(e a lista completa de argumentos). Se não houvesse links simbólicos, eu simplesmente mudaria do_stuff
para do_stuff_real
e escreveria um script
#!/bin/sh
echo "$0 $@" >> logfile
/usr/bin/do_stuff_real "$@"
No entanto, como eu sei que ele examinará o nome pelo qual é chamado, isso não funcionará. Como alguém escreve um script para obter o mesmo, mas ainda assim passa para do_stuff
o 'nome executável usado' certo?
Para o registro, para evitar respostas nessas linhas:
- Eu sei que posso fazê-lo em C (usando execve), mas seria muito mais fácil se eu pudesse, nesse caso, usar apenas um script de shell.
- Não posso simplesmente substituir
do_stuff
por um programa de registro.
fonte
sh
, você pode usar emmybase=${0##*/}
vez de basename.basename
invocação como essabasename -- foo.bar
não é familiar para mim, e no sistema Linux em que a testei, produz o resultadofoo.bar
que quebraria o script. Tem certeza de que é um método comum?basename -- foo.bar
retornafoo.bar
,basename -- --foo--/bar
retornabar
como esperado.basename "$foo"
só funciona se você pode garantir$foo
que não comece com a-
. A sintaxe geral para chamar um comando com argumentos arbitrários écmd -x -y -- "$argument"
.cmd "$argument"
está errado, a menos que você queira dizercmd "$option_or_arg"
. Agora, alguns comandos (incluindo algumas implementações históricas debasename
) não são compatíveis,--
portanto, às vezes, você pode escolher entre portabilidade e confiabilidade.Você pode usar
exec -a
(como encontrado embash
,ksh93
,zsh
,mksh
,yash
, mas não POSIX ainda) que é usado para especificar umargv[0]
a um comando a ser executado:Observe que não
$0
é o que o comando recebe. É o caminho do script como passado para (e que é passado como argumento para ), mas isso provavelmente será suficiente para o seu propósito.argv[0]
execve()
bash
Como exemplo, se
make_tea
foi chamado como:Como um shell normalmente faria ao chamar o comando pelo nome (procurando o executável em
$PATH
), o wrapper deveria:Isso não é:
mas isso é bom o suficiente, como se
do_stuff_real
sabe, para fazer chá.Onde isso seria um problema é se
do_stuff
foi invocado como:pois isso seria traduzido para:
Isso não aconteceria durante operações normais, mas observe que nosso invólucro faz algo assim.
Na maioria dos sistemas, o
argv[0]
conforme passado para o script é perdido depois que o intérprete (aqui/bin/bash
) é executado ( oargv[0]
intérprete na maioria dos sistemas é o caminho fornecido na linha she-bang ), portanto não há nada que um script de shell possa fazer a respeito.Se você quisesse transmitir
argv[0]
adiante, seria necessário compilar um executável. Algo como:fonte
perl
oupython
se disponível. As versões mais antigas dozsh
não eram compatíveisexec -a
, mas você sempre pode usá-loARGV0=the-argv-0 cmd args
.zsh
(embora agora você tenha deixado claro que não), mas era muito antigo, você ainda poderia usáARGV0
-lo.