Я предполагаю, что у вас есть сценарий оболочки, который вы хотите выполнить так, чтобы сам процесс сценария получил новый argv[0]
. Например (я только что проверил это в bash, поэтому я использую это, но это может работать в другом месте).
#!/bin/bash
echo "process $$ here, first arg was $1"
ps -p $$
Вывод будет примерно таким:
$ ./script arg1
process 70637 here, first arg was arg1
PID TTY TIME CMD
70637 ttys003 0:00.00 /bin/bash ./script arg1
Итак, ps
показывает оболочку, /bin/bash
в данном случае. Теперь попробуйте интерактивную оболочку exec -a
, но в подоболочке, чтобы не сдуть интерактивную оболочку:
$ (exec -a MyScript ./script arg1)
process 70936 here, first arg was arg1
PID TTY TIME CMD
70936 ttys008 0:00.00 /bin/bash /path/to/script arg1
Woops, все еще показывая /bin/bash
. что случилось? exec -a
, вероятно, установил argv[0]
, но затем начался новый экземпляр bash, потому что операционная система прочитала #!/bin/bash
в верхней части вашего скрипта. Хорошо, что если мы как-нибудь выполним exec'ing внутри скрипта? Во-первых, нам нужен какой-то способ определить, является ли это «первым» выполнением скрипта или вторым экземпляром exec
ed, в противном случае второй экземпляр будет выполняться снова и снова и снова в бесконечном цикле. Далее нам нужен исполняемый файл, чтобы , а не был файлом со строкой #!/bin/bash
вверху, чтобы ОС не смогла изменить желаемое значение argv [0]. Вот моя попытка:
$ cat ./script
#!/bin/bash
__second_instance="__second_instance_$$"
[[ -z ${!__second_instance} ]] && {
declare -x "__second_instance_$$=true"
exec -a MyScript "$SHELL" "$0" "$@"
}
echo "process $$ here, first arg was $1"
ps -p $$
Благодаря этому ответу я сначала проверяю переменную среды __second_instance_$$
, основанную на PID (который не изменяется через exec
), чтобы он не конфликтовал с другими сценариями, используя эта техника. Если он пуст, я предполагаю, что это первый экземпляр, и я экспортирую эту переменную среды, а затем exec. Но, что важно, я не исполняю этот сценарий, а исполняю двоичный файл оболочки напрямую, используя этот сценарий ($0
) в качестве аргумента, передавая также все остальные аргументы ($@
). Переменная окружения немного взломана.
Теперь вывод такой:
$ ./script arg1
process 71143 here, first arg was arg1
PID TTY TIME CMD
71143 ttys008 0:00.01 MyScript ./script arg1
Это почти там. argv[0]
- это MyScript
, как я хочу, но есть дополнительный аргумент ./script
, который является следствием непосредственного выполнения оболочки (а не обработки #!
в ОС). К сожалению, я не знаю, как лучше, чем этот.
Обновление для Bash 5.0
Похоже, в Bash 5.0 добавлена поддержка записи в специальную переменную BASH_ARGV0 , поэтому это должно стать намного проще.
(см. объявление о выпуске )