Siempre puede decirle a su shell que diga a las aplicaciones qué código de shell condujo a su ejecución. Por ejemplo, con zsh
, al pasar esa información en la $SHELL_CODE
variable de entorno usando el preexec()
gancho ( printenv
usado como ejemplo, usaría getenv("SHELL_CODE")
en su 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 esos se ejecutarían printenv
como:
execve("/usr/bin/printenv", ["printenv", "SHELL_CODE"],
["PATH=...", ..., "SHELL_CODE=..."]);
Permitiendo printenv
recuperar el código zsh que condujo a la ejecución de printenv
esos argumentos. Lo que desearía hacer con esa información no me queda claro.
Con bash
, la característica más cercana a zsh
's preexec()
sería usarla $BASH_COMMAND
en una DEBUG
trampa, pero tenga en cuenta que bash
tiene cierto nivel de reescritura en eso (y en particular refactoriza parte del espacio en blanco utilizado como delimitador) y eso se aplica a cada comando (bueno, algunos) ejecutar, no toda la línea de comando como se ingresó en el indicador (ver también la functrace
opción).
$ 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')
Vea cómo algunos de los espacios que son delimitadores en la sintaxis del lenguaje de shell se han comprimido en 1 y cómo no la línea de comando completa no siempre se pasa al comando. Probablemente no sea útil en su caso.
Tenga en cuenta que no recomendaría hacer este tipo de cosas, ya que potencialmente está filtrando información confidencial a cada comando como en:
echo very_secret | wc -c | untrustedcmd
filtraría ese secreto a ambos wc
y untrustedcmd
.
Por supuesto, podría hacer ese tipo de cosas para otros idiomas además del shell. Por ejemplo, en C, podría usar algunas macros que exportan el código C que ejecuta un comando al entorno:
#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;
}
Ejemplo:
$ ./a.out printenv C_CODE
execlp("printenv", "printenv", "C_CODE", NULL)
0 + execlp("printenv", "printenv", "C_CODE", NULL)
execvp(argv[1], &argv[1])
Vea cómo el preprocesador C condensó algunos espacios como en el caso bash. En la mayoría de los idiomas, si no en todos, la cantidad de espacio utilizado en los delimitadores no hace ninguna diferencia, por lo que no es sorprendente que el compilador / intérprete se tome algo de libertad aquí.