Você sempre pode dizer ao seu shell para informar aos aplicativos qual código shell leva à sua execução. Por exemplo, com zsh
, passando essas informações na variável de ambiente $SHELL_CODE
usando o preexec()
hook ( 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 os que executam printenv
como:
execve("/usr/bin/printenv", ["printenv", "SHELL_CODE"],
["PATH=...", ..., "SHELL_CODE=..."]);
Permitindo que printenv
recupere o código zsh que leva à execução de printenv
com esses argumentos. O que você gostaria de fazer com essa informação não está claro para mim.
Com bash
, o recurso mais próximo de zsh
' preexec()
estaria usando sua $BASH_COMMAND
em DEBUG
trap, mas observe que bash
faz algum nível de reescrita nisso (e em Refatorar alguns dos espaços em branco usados como delimitador) e isso é aplicado a toda execução de comando (bem, algumas), não à linha de comando inteira como inserida no prompt (consulte também a opção functrace
).
$ 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 espremidos em 1 e como a linha de comando completa nem sempre é passada para o comando. Então provavelmente não é útil no seu caso.
Note que eu não aconselharia fazer esse tipo de coisa, já que você está potencialmente vazando informações confidenciais para todos os comandos, como em:
echo very_secret | wc -c | untrustedcmd
vazaria esse segredo para 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, se não em todas as linguagens, a quantidade de espaço usada nos delimitadores não faz diferença, portanto, não é surpresa que o compilador / intérprete tenha alguma liberdade com eles aqui.