Vous pouvez toujours dire à votre shell d'indiquer aux applications quel code shell mène à leur exécution. Par exemple, avec zsh
, en passant ces informations dans la $SHELL_CODE
variable d'environnement en utilisant le preexec()
hook ( printenv
utilisé comme exemple, vous utiliseriez getenv("SHELL_CODE")
dans votre programme):
$ 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
Tous ceux-ci s'exécuteraient printenv
comme:
execve("/usr/bin/printenv", ["printenv", "SHELL_CODE"],
["PATH=...", ..., "SHELL_CODE=..."]);
Permet printenv
de récupérer le code zsh qui a conduit à l'exécution de printenv
ces arguments. Ce que vous voudriez faire de ces informations ne m'est pas clair.
Avec bash
, la fonctionnalité la plus proche de zsh
s preexec()
utiliserait son $BASH_COMMAND
dans un DEBUG
piège, mais notez que cela bash
fait un certain niveau de réécriture dans cela (et en particulier refacteurs certains des espaces utilisés comme délimiteur) et qui est appliqué à chaque commande (enfin, certains) exécutez, pas la ligne de commande entière comme entrée à l'invite (voir aussi l' functrace
option).
$ 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')
Voyez comment certains des espaces qui sont des délimiteurs dans la syntaxe du langage shell ont été compressés en 1 et comment la ligne de commande complète n'est pas toujours transmise à la commande. Donc probablement pas utile dans votre cas.
Notez que je ne conseillerais pas de faire ce genre de chose, car vous risquez de divulguer des informations sensibles à chaque commande comme dans:
echo very_secret | wc -c | untrustedcmd
divulguerait ce secret à la fois wc
et untrustedcmd
.
Bien sûr, vous pourriez faire ce genre de chose pour d'autres langues que le shell. Par exemple, en C, vous pouvez utiliser certaines macros qui exportent le code C qui exécute une commande vers l'environnement:
#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;
}
Exemple:
$ ./a.out printenv C_CODE
execlp("printenv", "printenv", "C_CODE", NULL)
0 + execlp("printenv", "printenv", "C_CODE", NULL)
execvp(argv[1], &argv[1])
Voyez comment certains espaces ont été condensés par le pré-processeur C comme dans le cas bash. Dans la plupart, sinon toutes les langues, la quantité d'espace utilisée dans les délimiteurs ne fait aucune différence, il n'est donc pas surprenant que le compilateur / interprète prenne une certaine liberté avec eux ici.