递归替换变量
Recursively replacement on a variable
给定这个关联数组:
declare -A variables=(
[prefix]='/usr'
[exec_prefix]='@prefix@'
[libdir]='@exec_prefix@/lib'
)
我想用与捕获关联的值(例如 /usr
for prefix
) 在其所有值中,以便递归执行替换,直到不再出现为止。数组中每个键的步骤为:
- 检索与其关联的值并对其执行 (2)。
- 检查给定字符串中是否有匹配的模式。
- 如果没有,return给定的字符串。
- 如果有匹配项:
- 对捕获执行 (1) 并保留结果。
- 用结果替换匹配项。
- 对结果字符串执行 (2)。
- 删除与键关联的先前值并将最后一个字符串关联到它 returned.
无论采用哪种方法,期望的结果都是:
prefix=/usr
exec_prefix=/usr
libdir=/usr/lib
附加要求:
- 不会出现自引用(例如
prefix=@prefix@
)。
- 如果可能,仅使用 Bash 内置函数。
Lua中的示例:
local variables={
prefix="/usr",
exec_prefix="@prefix@",
includedir="@prefix@/include",
libdir="@exec_prefix@/lib",
random_one_to_show_off_fancy_recursion="@prefix@@libdir@@includedir@"
}
function replacer( variable )
return compute_value(variables[variable])
end
function compute_value( s )
return s:gsub('@([^@/]+)@',replacer)
end
local variable, value = next(variables)
while variable do
variables[variable] = compute_value(value)
print( string.format('%-39s\t%s', variable, variables[variable]) )
variable, value = next(variables,variable)
end
下面的(纯 Bash)代码假设当 'xyz' 不是变量时,“@@”保持不变,“@xyz@”保持不变。它还尝试检测递归变量定义,包括间接变量定义(例如 [a]=@b@ [b]=@c@ [c]=@a@
)。
# Regular expression for a string with an embedded expansion
# For a string of the form 'u@v@w', where 'u' and 'v' do not contain '@':
# u -> BASH_REMATCH[1]
# v -> BASH_REMATCH[2]
# w -> BASH_REMATCH[3]
readonly EXPANSION_RX='^([^@]*)@([^@]*)@(.*)$'
# First pass tries to expand all variables
vars_to_expand=( "${!variables[@]}" )
while (( ${#vars_to_expand[*]} > 0 )) ; do
old_vars_to_expand=( "${vars_to_expand[@]}" )
vars_to_expand=()
for var in "${old_vars_to_expand[@]}" ; do
val=${variables[$var]}
unexpanded=$val
newval=
while [[ $unexpanded =~ $EXPANSION_RX ]] ; do
newval+=${BASH_REMATCH[1]}
v=${BASH_REMATCH[2]}
unexpanded=${BASH_REMATCH[3]}
if [[ $v == "$var" ]] ; then
echo "ERROR - Expanding '@$var@' in '$var'" >&2
exit 1
elif [[ -z $v ]] ; then
# The empty string can not be a hash key (Duh!)
newval+=@$v@
else
newval+=${variables[$v]-@$v@}
fi
done
newval+=$unexpanded
if [[ $newval != "$val" ]] ; then
# An expansion has occurred.
# Update the variable value
variables[$var]=$newval
# Further expansions may be possible, so add the variable to the
# list of variables to be expanded again
vars_to_expand+=( "$var" )
fi
done
done
给定这个关联数组:
declare -A variables=(
[prefix]='/usr'
[exec_prefix]='@prefix@'
[libdir]='@exec_prefix@/lib'
)
我想用与捕获关联的值(例如 /usr
for prefix
) 在其所有值中,以便递归执行替换,直到不再出现为止。数组中每个键的步骤为:
- 检索与其关联的值并对其执行 (2)。
- 检查给定字符串中是否有匹配的模式。
- 如果没有,return给定的字符串。
- 如果有匹配项:
- 对捕获执行 (1) 并保留结果。
- 用结果替换匹配项。
- 对结果字符串执行 (2)。
- 删除与键关联的先前值并将最后一个字符串关联到它 returned.
无论采用哪种方法,期望的结果都是:
prefix=/usr
exec_prefix=/usr
libdir=/usr/lib
附加要求:
- 不会出现自引用(例如
prefix=@prefix@
)。 - 如果可能,仅使用 Bash 内置函数。
Lua中的示例:
local variables={
prefix="/usr",
exec_prefix="@prefix@",
includedir="@prefix@/include",
libdir="@exec_prefix@/lib",
random_one_to_show_off_fancy_recursion="@prefix@@libdir@@includedir@"
}
function replacer( variable )
return compute_value(variables[variable])
end
function compute_value( s )
return s:gsub('@([^@/]+)@',replacer)
end
local variable, value = next(variables)
while variable do
variables[variable] = compute_value(value)
print( string.format('%-39s\t%s', variable, variables[variable]) )
variable, value = next(variables,variable)
end
下面的(纯 Bash)代码假设当 'xyz' 不是变量时,“@@”保持不变,“@xyz@”保持不变。它还尝试检测递归变量定义,包括间接变量定义(例如 [a]=@b@ [b]=@c@ [c]=@a@
)。
# Regular expression for a string with an embedded expansion
# For a string of the form 'u@v@w', where 'u' and 'v' do not contain '@':
# u -> BASH_REMATCH[1]
# v -> BASH_REMATCH[2]
# w -> BASH_REMATCH[3]
readonly EXPANSION_RX='^([^@]*)@([^@]*)@(.*)$'
# First pass tries to expand all variables
vars_to_expand=( "${!variables[@]}" )
while (( ${#vars_to_expand[*]} > 0 )) ; do
old_vars_to_expand=( "${vars_to_expand[@]}" )
vars_to_expand=()
for var in "${old_vars_to_expand[@]}" ; do
val=${variables[$var]}
unexpanded=$val
newval=
while [[ $unexpanded =~ $EXPANSION_RX ]] ; do
newval+=${BASH_REMATCH[1]}
v=${BASH_REMATCH[2]}
unexpanded=${BASH_REMATCH[3]}
if [[ $v == "$var" ]] ; then
echo "ERROR - Expanding '@$var@' in '$var'" >&2
exit 1
elif [[ -z $v ]] ; then
# The empty string can not be a hash key (Duh!)
newval+=@$v@
else
newval+=${variables[$v]-@$v@}
fi
done
newval+=$unexpanded
if [[ $newval != "$val" ]] ; then
# An expansion has occurred.
# Update the variable value
variables[$var]=$newval
# Further expansions may be possible, so add the variable to the
# list of variables to be expanded again
vars_to_expand+=( "$var" )
fi
done
done