Ви завжди можете сказати своїй оболонці, щоб сказати програмам, який код оболонки призводить до їх виконання. Наприклад, zsh
передаваючи цю інформацію в $SHELL_CODE
змінну оточення, використовуючи preexec()
гачок ( printenv
як приклад, який ви використовуєте getenv("SHELL_CODE")
у своїй програмі):
$ 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
Усі вони виконуватимуться printenv
як:
execve("/usr/bin/printenv", ["printenv", "SHELL_CODE"],
["PATH=...", ..., "SHELL_CODE=..."]);
Дозвіл printenv
на отримання zsh-коду, що призводить до виконання printenv
цих аргументів. Що б ви хотіли зробити з цією інформацією, мені незрозуміло.
З bash
, найбільш близькою до zsh
's функцією preexec()
буде використання його $BASH_COMMAND
в DEBUG
пастці, але зауважте, що в цьому bash
певний рівень перезапису (і, зокрема, рефактори, частина білого простору, що використовується як роздільник), застосовується до кожної (ну, деякої) команди запустити, а не весь командний рядок, як було введено у підказці (див. також 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')
Подивіться, як деякі пробіли, які є роздільниками в синтаксисі мови оболонки, були видавлені в 1, і як не повний командний рядок не завжди передається команді. Тому, напевно, не корисно у вашому випадку.
Зауважте, що я б не радив робити подібні дії, оскільки ви потенційно пропускаєте конфіденційну інформацію до кожної команди, як у:
echo very_secret | wc -c | untrustedcmd
витікав би цю таємницю для обох wc
і untrustedcmd
.
Звичайно, ви могли б зробити таку річ для інших мов, крім оболонки. Наприклад, в C ви можете використовувати деякі макроси, які експортують код C, який виконує команду в середовище:
#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;
}
Приклад:
$ ./a.out printenv C_CODE
execlp("printenv", "printenv", "C_CODE", NULL)
0 + execlp("printenv", "printenv", "C_CODE", NULL)
execvp(argv[1], &argv[1])
Подивіться, як деякі простори були ущільнені попереднім процесором C, як у випадку з bash. У більшості, якщо не у всіх мовах, обсяг простору, який використовується в роздільниках, не має ніякої різниці, тому не дивно, що компілятор / інтерпретатор тут трохи сміливий.