Основная идея заключается в том, что VAR=VALUE some-commandнаборы VARдля VALUEдля исполнения , some-commandкогда some-commandесть внешняя команда, и она не получает больше фантазии , чем это. Если вы объедините эту интуицию с некоторыми знаниями о том, как работает оболочка, вы должны придумать правильный ответ в большинстве случаев. Ссылка на POSIX - «Простые команды» в главе «Язык команд оболочки» .
Если some-commandэто внешняя команда , VAR=VALUE some-commandэквивалентно env VAR=VALUE some-command. VARэкспортируется в среде some-command, и его значение (или отсутствие значения) в оболочке не изменяется.
Если some-commandэто функция , то VAR=VALUE some-commandэто эквивалентно VAR=VALUE; some-command, т.е. назначение остается на месте после того, как функция вернулась, и переменная не экспортируется в среду. Причина этого связана с разработкой оболочки Bourne (и, следовательно, с обратной совместимостью): у нее не было возможности сохранять и восстанавливать значения переменных при выполнении функции. Не экспортировать переменную имеет смысл, так как функция выполняется в самой оболочке. Однако ksh (включая ATT ksh93 и pdksh / mksh), bash и zsh реализуют более полезное поведение, VARкоторое задается только во время выполнения функции (также экспортируется). В ksh это делается, если функция определена с синтаксисом kshfunction NAME …не, если это определено со стандартным синтаксисом NAME (). В bash это делается только в режиме bash, а не в режиме POSIX (при запуске с POSIXLY_CORRECT=1). В zsh это делается, если posix_builtinsопция не установлена; эта опция не установлена по умолчанию, но включена emulate shили emulate ksh.
Если some-commandявляется встроенным, поведение зависит от типа встроенного. Специальные встроенные функции ведут себя как функции. Специальные встроенные модули - это те, которые должны быть реализованы внутри оболочки, потому что они влияют на оболочку состояния (например, breakвлияют на поток управления, cdвлияют на текущий каталог, setвлияют на позиционные параметры и опции…). Другие встроенные функции встроены только для повышения производительности и удобства (в основном - например, функция bash printf -vможет быть реализована только встроенной функцией ), и они ведут себя как внешняя команда.
Назначение происходит после раскрытия псевдонима, поэтому, если some-commandэто псевдоним , сначала разверните его, чтобы выяснить, что происходит.
Обратите внимание, что во всех случаях назначение выполняется после анализа командной строки, включая любые подстановки переменных в самой командной строке. Таким образом, var=a; var=b echo $varпечатает a, потому что $varоценивается до того, как назначение имеет место. И таким образом IFS=. printf "%s\n" $varиспользует старое IFSзначение для разделения $var.
Я рассмотрел все типы команд, но есть еще один случай: когда нет команды для выполнения , т.е. если команда состоит только из назначений (и, возможно, перенаправлений). В этом случае назначение остается на месте . VAR=VALUE OTHERVAR=OTHERVALUEэквивалентно VAR=VALUE; OTHERVAR=OTHERVALUE. Таким образом , после того IFS=. arr=($var), IFSостается равным .. Поскольку вы можете использовать $IFSв присваивании arrс ожиданием того, что оно уже имеет новое значение, имеет смысл использовать новое значение IFSдля расширения $var.
Таким образом, вы можете использовать только IFSдля временного разделения поля:
- путем запуска новой оболочки или подоболочки (например
third=$(IFS=.; set -f; set -- $var; echo "$3"), это сложный способ, за third=${var#*.*.}исключением того, что они ведут себя по-разному, если значение varсодержит менее двух .символов);
- в ksh,
IFS=. some-functionгде some-functionопределяется с помощью синтаксиса ksh function some-function …;
- в bash и zsh, при
IFS=. some-functionусловии, что они работают в основном режиме, а не в режиме совместимости.
IFSостается установленным." Eek. После прочтения первой части это имеет смысл, но до того, как я разместил этот вопрос, я бы этого не ожидал.