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_CODEvariable d'environnement en utilisant le preexec()hook ( printenvutilisé 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 printenvcomme:
execve("/usr/bin/printenv", ["printenv", "SHELL_CODE"],
["PATH=...", ..., "SHELL_CODE=..."]);
Permet printenvde récupérer le code zsh qui a conduit à l'exécution de printenvces arguments. Ce que vous voudriez faire de ces informations ne m'est pas clair.
Avec bash, la fonctionnalité la plus proche de zshs preexec()utiliserait son $BASH_COMMANDdans un DEBUGpiège, mais notez que cela bashfait 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' functraceoption).
$ 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 wcet 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.