Puoi sempre dire alla tua shell di dire alle applicazioni quale codice della shell porta alla loro esecuzione. Ad esempio, con zsh
, passando quelle informazioni nella $SHELL_CODE
variabile d'ambiente usando l' preexec()
hook ( printenv
usato come esempio, useresti getenv("SHELL_CODE")
nel tuo programma):
$ 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
Tutti quelli sarebbero eseguiti printenv
come:
execve("/usr/bin/printenv", ["printenv", "SHELL_CODE"],
["PATH=...", ..., "SHELL_CODE=..."]);
Permettere printenv
di recuperare il codice zsh che porta all'esecuzione di printenv
con quegli argomenti. Quello che vorresti fare con queste informazioni non mi è chiaro.
Con bash
, la caratteristica più vicina a quella che zsh
userebbe preexec()
sarebbe la sua $BASH_COMMAND
in una DEBUG
trappola, ma nota che bash
fa un certo livello di riscrittura in quello (e in particolare i refactor alcuni degli spazi bianchi usati come delimitatore) e che viene applicato a ogni (bene, alcuni) comando eseguire, non l'intera riga di comando immessa al prompt (vedere anche l' functrace
opzione).
$ 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')
Guarda come alcuni degli spazi che sono delimitatori nella sintassi del linguaggio shell sono stati compressi in 1 e come non sempre la riga di comando completa non viene sempre passata al comando. Quindi probabilmente non è utile nel tuo caso.
Nota che non consiglierei di fare questo tipo di cose, poiché potenzialmente stai perdendo informazioni sensibili ad ogni comando come in:
echo very_secret | wc -c | untrustedcmd
perderebbe quel segreto a entrambi wc
e untrustedcmd
.
Certo, potresti fare quel genere di cose per altre lingue oltre alla shell. Ad esempio, in C, è possibile utilizzare alcune macro che esportano il codice C che esegue un comando nell'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;
}
Esempio:
$ ./a.out printenv C_CODE
execlp("printenv", "printenv", "C_CODE", NULL)
0 + execlp("printenv", "printenv", "C_CODE", NULL)
execvp(argv[1], &argv[1])
Guarda come alcuni spazi sono stati condensati dal pre-processore C come nel caso bash. Nella maggior parte, se non in tutte le lingue, la quantità di spazio utilizzata nei delimitatori non fa alcuna differenza, quindi non sorprende che il compilatore / interprete si prenda qualche libertà con loro qui.