Вы всегда можете указать своей оболочке сообщить приложениям, какой код оболочки приводит к их выполнению. Например, с 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. В большинстве, если не во всех языках, объем пространства, используемого в разделителях, не имеет значения, поэтому не удивительно, что компилятор / интерпретатор берет на себя некоторую свободу здесь.