Você sempre pode dizer ao seu shell para dizer aos aplicativos que código de shell leva à sua execução. Por exemplo, com zsh
, passando essas informações na $SHELL_CODE
variável de ambiente usando o preexec()
gancho ( printenv
usado como exemplo, você usaria getenv("SHELL_CODE")
em seu programa):
$ preexec() export SHELL_CODE=$1
$ printenv SHELL_CODE
printenv SHELL_CODE
$ printenv SHELL_CODE
printenv CODE
$ $(echo printenv SHELL_CODE)
$(echo printenv SHELL_CODE)
$ for i in SHELL_CODE; do printenv "$i"; done
for i in SHELL_CODE; do printenv "$i"; done
$ printenv SHELL_CODE; : other command
printenv SHELL_CODE; : other command
$ f() printenv SHELL_CODE
$ f
f
Todos aqueles seriam executados printenv
como:
execve("/usr/bin/printenv", ["printenv", "SHELL_CODE"],
["PATH=...", ..., "SHELL_CODE=..."]);
Permitindo printenv
recuperar o código zsh que leva à execução printenv
com esses argumentos. O que você gostaria de fazer com essas informações não está claro para mim.
Com bash
, o recurso mais próximo zsh
's preexec()
estaria usando seu $BASH_COMMAND
em uma DEBUG
armadilha, mas nota que bash
faz algum nível de reescrever em que (e em refatora particulares alguns dos espaços em branco usado como delimitador) e que é aplicado a cada (bem, alguns) de comando executar, não toda a linha de comando, conforme inserido no prompt (consulte também a functrace
opção).
$ trap 'export SHELL_CODE="$BASH_COMMAND"' DEBUG
$ printenv SHELL_CODE
printenv SHELL_CODE
$ printenv $(echo 'SHELL_CODE')
printenv $(echo 'SHELL_CODE')
$ for i in SHELL_CODE; do printenv "$i"; done; : other command
printenv "$i"
$ printf '%s\n' "$(printenv "SHELL_CODE")"
printf '%s\n' "$(printenv "SHELL_CODE")"
$ set -o functrace
$ printf '%s\n' "$(printenv "SHELL_CODE")"
printenv "SHELL_CODE"
$ print${-+env } $(echo 'SHELL_CODE')
print${-+env } $(echo 'SHELL_CODE')
Veja como alguns dos espaços delimitadores na sintaxe da linguagem shell foram compactados em 1 e como nem toda a linha de comando nem sempre é passada para o comando. Então provavelmente não é útil no seu caso.
Observe que eu não recomendaria esse tipo de coisa, pois você está potencialmente vazando informações confidenciais para todos os comandos, como em:
echo very_secret | wc -c | untrustedcmd
vazaria esse segredo para ambos wc
e untrustedcmd
.
Claro, você poderia fazer esse tipo de coisa para outros idiomas além do shell. Por exemplo, em C, você pode usar algumas macros que exportam o código C que executa um comando para o ambiente:
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#define WRAP(x) (setenv("C_CODE", #x, 1), x)
int main(int argc, char *argv[])
{
if (!fork()) WRAP(execlp("printenv", "printenv", "C_CODE", NULL));
wait(NULL);
if (!fork()) WRAP(0 + execlp("printenv", "printenv", "C_CODE", NULL));
wait(NULL);
if (argc > 1 && !fork()) WRAP(execvp(argv[1], &argv[1]));
wait(NULL);
return 0;
}
Exemplo:
$ ./a.out printenv C_CODE
execlp("printenv", "printenv", "C_CODE", NULL)
0 + execlp("printenv", "printenv", "C_CODE", NULL)
execvp(argv[1], &argv[1])
Veja como alguns espaços foram condensados pelo pré-processador C, como no caso do bash. Na maioria dos idiomas, se não em todos os idiomas, a quantidade de espaço usada nos delimitadores não faz diferença; portanto, não é de surpreender que o compilador / intérprete tenha alguma liberdade com eles aqui.