Не так просто поддерживать local
или нет. Существует множество вариаций синтаксиса и того, как это делается между оболочками, которые имеют ту или иную форму локальной области видимости.
Вот почему очень трудно придумать стандарт, который устраивал бы всех. См.http://austingroupbugs.net/bug_view_page.php?bug_id=767об усилиях POSIX в этом направлении.
локальная область видимости была впервые добавлена в ksh в начале 80-х.
Синтаксис для объявления локальной переменной в функции был сtypeset
:
function f {
typeset var=value
set -o noglob # also local to the function
...
}
(поддержка функций была добавлена в оболочку Bourne позже, но с другим синтаксисом(f() command
)и ksh
добавлена поддержка и этой позже; оболочка Bourne никогда не имела локальной области видимости (, за исключением, конечно, подоболочек))
Встроенный AFAIK local
был впервые добавлен в оболочку Almquist (, используемую в BSD, dash, busybox sh )в 1989 году, но работает значительно иначе, чем ksh
typeset
. Производные ash
не поддерживают typeset
в качестве псевдонима для local
, но вы всегда можете определить его вручную.
bash и zsh добавили typeset
с псевдонимом local
в 1989 и 1991 годах соответственно.
ksh88 добавлен local
в качестве недокументированного псевдонима к typeset
приблизительно в 1990 г., а pdksh и его производным – в 1994 г.posh
(на основеpdksh
)удаленоtypeset
(для строгого соответствия Политике Debian, которая требует local
, но неtypeset
).
Первоначально POSIX возражал против определения typeset
на том основании, что это была динамическая область видимости.Итак, ksh93 (, переписанный в 1993 году Дэвидом Корном )ksh, переключился на статическую область видимости. Кроме того, в ksh93, в отличие от ksh88, локальная область видимости выполняется только для функций, объявленных с синтаксисом ksh
(function f {...}
), а не синтаксисом Борна (f() {...}
), а псевдоним local
был удален.
Однако бета-версия ksh93v -и окончательная версия от AT&T могут быть скомпилированы с экспериментальным режимом «bash» (, фактически включенным по умолчанию ), который выполняет динамическую область видимости (в любых формах функций, в том числе с local
и typeset
), когда ksh93
вызывается как bash
. local
отличается от typeset
в этом случае тем, что его можно вызвать только из функции. Этот режим bash
будет отключен по умолчанию в ksh2020 , хотя псевдонимы local
/ declare
для typeset
будут сохранены, даже если режим bash не скомпилирован в(хотя все еще со статической областью видимости ).
yash
(написан намного позже ), имеетtypeset
(а-ля ksh88 ), но имеет псевдоним local
только с версии 2.48 (декабря 2018 ).
@Schily поддерживает потомок оболочки Bourne, который недавно стал в основном совместимым с POSIX, называемый bosh
, который поддерживает локальную область видимости с версии 2016 -07 -06 (с local
, аналогично кash
).
Таким образом,:
подобные Bourne -оболочки, которые имеют некоторую форму локальной области видимости для переменных,:
Что касается sh
различных систем, обратите внимание, что есть системы, в которых POSIX sh
находится в/bin
(больше всего ),и другие, где это не так (, как Solaris, где это/usr/xpg4/bin
). Для реализации sh
на различных системах имеем:
Теперь, чем они отличаются:
typeset
(ksh, pdksh, bash, zsh, yash )vslocal
(ksh88, pdksh, bash, zsh, ash, yash 2.48+ ). function f {...}
функция ), по сравнению с динамической областью видимости (во всех остальных оболочках ). Например, function f { typeset v=1; g; echo "$v"; }; function g { v=2; }; f
выводит 1
или 2
. См. также, как атрибут export
влияет на область видимости в ksh93
. local
/ typeset
просто переменную локальной (ash
,bosh
)или создает новый экземпляр переменной (другие оболочки ). Например, если v=1; f() { local v; echo "${v:-empty}"; }; f
выводит 1
или empty
(, см. также параметр localvar_inherit
в bash 5.0 и выше ). export
)и/или тип, и какие из переменных в родительской области. Например, печатает ли export V=1; f() { local V=2; printenv V; }; f
1
, 2
или ничего. zsh
)или она изначально не установлена. unset V
для переменной в локальной области видимости оставить переменную unset
или просто очистить один уровень области видимости (mksh
, yash
, bash
при некоторых обстоятельствах ).Например, независимо от того, выводит ли v=1; f() { local v=2; unset v; echo "$v"; }
1
или ничего (, см. также параметр localvar_unset
в bash 5.0 и выше )export
, является ли это ключевым словом или просто встроенной функцией или и тем, и другим, и при каких условиях оно считается ключевым словом. export
, анализируются ли аргументы как обычные аргументы команды или как присваивания (и при каком условии ). v=value myfunction
, где myfunction
сам объявляет v
локальным или нет. Это те, о которых я сейчас думаю. Проверьте ошибку группы austin выше для получения более подробной информации.
Что касается локальной области видимости для опций(оболочки, в отличие от переменных ), оболочки, поддерживающие ее:
ksh88
(с синтаксисом определения функции ):, выполненным по умолчанию, я не знаю, как его отключить. ash
(с 1989 г. ):с local -
. Это делает параметр $-
(, в котором хранится список опций ), локальным. ksh93
:теперь выполняется только для функций function f {...}
. zsh
(с 1995 года ). С setopt localoptions
. Также с emulate -L
для режима эмуляции (и его набора опций ), которые должны быть сделаны локальными для функции. bash
(с 2016 года )с local -
, как в ash
, но только для опций, управляемых set
, а не тех, которыми управляет shopt
. ¹ POSIX sh
в Solaris — это /usr/xpg4/bin/sh
(, хотя в нем много ошибок совместимости, включая локальные опции для функций ). /bin/sh
до Solaris 10 была оболочка Bourne (, поэтому не было локальной области видимости ), а поскольку Solaris 11 — это ksh93
Вам нужно использовать awk getline
для чтения вывода в переменную. Вам также необходимо правильно установить локаль, чтобы перекодирование работало должным образом. Попробуйте это:
$ LC_ALL=C gawk '/DESCRIPTION/{
"echo \""$0"\" | recode..html" | getline ff; print ff
}' file
<DESCRIPTION><p>foo</p><p> </p><p> </p></DESCRIPTION>
Предполагая, что документ правильно сформирован, с некоторым корневым узлом root
...
$ cat file.xml
<root>
<ITEM_ID>foo</ITEM_ID>
<PRODUCTNAME>bar</PRODUCTNAME>
<DESCRIPTION><p>foo</p><p> </p><p> </p></DESCRIPTION>
<URL>bar</URL>
<IMGURL>foo</IMGURL>
<IMGURL_ALTERNATIVE></IMGURL_ALTERNATIVE>
</root>
Затем,
$ xmlstarlet ed -u '/root/DESCRIPTION' -v "$( xmlstarlet sel -t -c '/root/DESCRIPTION/*' file.xml )" file.xml
<?xml version="1.0"?>
<root>
<ITEM_ID>foo</ITEM_ID>
<PRODUCTNAME>bar</PRODUCTNAME>
<DESCRIPTION><p>foo</p><p> </p><p> </p></DESCRIPTION>
<URL>bar</URL>
<IMGURL>foo</IMGURL>
<IMGURL_ALTERNATIVE/>
</root>
Здесь происходит то, что xmlstarlet sel
используется для извлечения копии узлов под узлом /root/DESCRIPTION
. Вот что делает xmlstarlet sel -t -c '/root/DESCRIPTION/*' file.xml
и возвращает строку <p>foo</p><p> </p><p> </p>
.
Затем эта строка используется в качестве нового текстового значения для узла /root/DESCRIPTION
с помощью команды xmlstarlet ed
. Новое значение получается из подстановки команды.
Обратите внимание, что значение автоматически кодируется XML.