Изменить параметр массива изнутри подоболочки

Изменить параметр массива изнутри подоболочки

Возможно ли shiftприсвоить значение параметру массива изнутри подоболочки?

Пример кода:

arr=(a b c)
(shift arr)
echo $arr
# prints: a b c
# should print: b c

решение1

В этом и заключается суть подоболочек — запустить часть кода в копии текущегосреда выполнения оболочки(подробности см. вспецификация POSIXдля sh), чтобы сохранить исходную, поэтому весь смысл в том, что любые изменения переменных, сделанные в подоболочке, будут потеряны после завершения подоболочки.

Традиционно это делается путем ответвления оболочки процесса и запуска кода в дочернем процессе, пока родительский процесс ждет его завершения.

POSIX не требует этого, и ksh93, по крайней мере, реализует (...)подоболочки, тщательно восстанавливая исходную среду после возврата подоболочки без разветвления процесса, если этого можно избежать (хотя иногда в некоторых особых случаях это не удается сделать должным образом).

zshделает fork процесса для этого, как и большинство других оболочек. Есть исключения для оптимизации, например, когда (...)подоболочка является последней командой в zsh -cскрипте:

$ zsh -c 'zmodload zsh/system; echo $$; (echo $sysparams[pid]; ps; ps)'
21085
21085
    PID TTY          TIME CMD
   1839 pts/4    00:00:00 zsh
  21085 pts/4    00:00:00 zsh
  21086 pts/4    00:00:00 ps
    PID TTY          TIME CMD
   1839 pts/4    00:00:00 zsh
  21085 pts/4    00:00:00 ps

Это тот же самый процесс 21085, который выполнил выше zsh, интерпретировал подоболочку и даже выполнил последнюю psкоманду.

Достаточно установить , trapчтобы сделать эту оптимизацию недействительной, суть в том, что это делается только в том случае, если zsh может гарантировать, что после возврата подоболочки оболочкой ничего не будет запущено.

Чтобы дочерний процесс мог изменить значение переменной в родительском процессе, ему необходимо будет выполнить такие действия, как присоединение gdbк этому процессу и внедрение в него кода для изменения внутренних структур памяти в этом процессе.

Если вы хотите получить значение массива, как определено подоболочкой, вам нужно, чтобы подоболочка передала свое определение родителю. Это может быть сделано, например, через:

eval "$(
  # also a subshell using $(...)
  arr=( a b c )
  typeset -p arr
)"

Затем typesetбудет выведено typeset -a arr=( a b c )(или typeset -g -a arr=( a b c )вызвано внутри функции), что после evalиспользования приведет к созданию той же переменной в родительской функции.

Кстати, вместо:

shift arr

Я хотел бы использовать:

shift 1 arr

или:

arr[1]=()

Часть shift arrкода неоднозначна, поскольку она означает разные вещи ( shift 1 arrvs shift arr argv) в зависимости от того, arrобъявлена ​​ли она как переменная массива или нет. Использование shift 1 arrделает более очевидным, что вам нужна именно первая.

решение2

Подоболочка — это отдельный процесс, он не может изменять родительский процесс.

Связанный контент