【问题标题】:Recursively replacement on a variable递归替换变量
【发布时间】:2016-04-01 19:12:33
【问题描述】:

给定这个关联数组:

declare -A variables=(
   [prefix]='/usr'
   [exec_prefix]='@prefix@'
   [libdir]='@exec_prefix@/lib'
)

我想将所有出现的模式@([^@/]+)@(例如@prefix@prefix 是捕获)替换为与捕获关联的值(例如/usr 代表prefix)它的值,以便递归执行替换,直到不再出现。数组中每个键的步骤是:

  1. 检索与其关联的值并对其执行 (2)。
  2. 检查给定字符串中的模式是否匹配。
    • 如果没有,则返回给定的字符串。
    • 如果有匹配项:
      1. 对捕获执行 (1) 并保留结果。
      2. 用结果替换匹配项。
      3. 对结果字符串执行 (2)。
  3. 删除与键关联的先前值,并将返回的最后一个字符串与其关联。

无论采用何种方法,期望的结果是:

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

【问题讨论】:

  • 您要么过度设计外壳解决方案,要么正在寻找免费咨询。 ;-) 。您尝试过什么来解决您的问题?也许您想为此提供 100 点赏金?祝你好运。
  • 这需要递归完成吗?这是干什么用的?
  • @shellter 绝对不是在寻找免费咨询!我没有发布任何我尝试过的东西,因为它真的很复杂。作为记录,我尝试了涉及eval的不同方法,面临几个问题,主要是扩展顺序(例如,libdir不应该在exec_prefix之前评估)。我最终得到了一个 Lua 脚本,我从中提取了上面的示例,但我不想让 Lua 成为对用户的要求。

标签: regex bash recursion replace substitution


【解决方案1】:

下面的(纯 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

【讨论】:

    猜你喜欢
    • 2016-05-17
    • 1970-01-01
    • 1970-01-01
    • 2019-06-21
    • 1970-01-01
    • 2018-12-29
    • 2013-02-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多