如何防止BASH_REMATCH漏出函数?

时间:2016-06-07 08:59:42

标签: bash memory-leaks

我想使用bash运算符+~首先拆分一个字符串,然后再次检查生成的字符串。当我尝试这个时,如果发现BASH_REMATCH的元素被第二次使用覆盖,那么母功能在第二次使用时失败。

以下面的构造示例为例:

#!/bin/bash

inputline="abc123ABC123abc,xyz890XYZ890xyz"

checkABC ()
{
    local teststring="$1"
    local pattern="([^,]+),(.*)"

    if [[ $teststring =~ $pattern ]]; then
        echo "${BASH_REMATCH[1]}; ${BASH_REMATCH[2]}"
        checkNum ${BASH_REMATCH[1]}
        checkNum ${BASH_REMATCH[2]}
    fi

}

checkNum ()
{
    if [[ $1 =~ [a-z]+([0-9]+)[A-Z]+([0-9]+)[a-z]+ ]]; then
        echo "${BASH_REMATCH[1]}; ${BASH_REMATCH[2]}"
    fi
}

set -x
checkABC $inputline

这将给出以下输出,我们可以看到${BASH_REMATCH[2]}如何被函数checkNum覆盖。

$ bash ./leaking.sh
+ checkABC abc123ABC123abc,xyz890XYZ890xyz
+ local teststring=abc123ABC123abc,xyz890XYZ890xyz
+ local 'pattern=([^,]+),(.*)'
+ [[ abc123ABC123abc,xyz890XYZ890xyz =~ ([^,]+),(.*) ]]
+ echo 'abc123ABC123abc; xyz890XYZ890xyz'
abc123ABC123abc; xyz890XYZ890xyz
+ checkNum abc123ABC123abc
+ [[ abc123ABC123abc =~ [a-z]+([0-9]+)[A-Z]+([0-9]+)[a-z]+ ]]
+ echo '123; 123'
123; 123
+ checkNum 123
+ [[ 123 =~ [a-z]+([0-9]+)[A-Z]+([0-9]+)[a-z]+ ]]

我知道我可以通过将重新匹配的结果复制到另一个数组来防止这种情况,我可以在本地处理并应用checkNum(参见下面的示例)。这是否是明智的做法,或者是否有更好的方法来阻止BASH_REMATCH泄漏出来?

此代码

#!/bin/bash

inputline="abc123ABC123abc,xyz890XYZ890xyz"

checkABC ()
{
    local teststring="$1"
    local pattern="([^,]+),(.*)"
    local -a storeRematch

    if [[ $teststring =~ $pattern ]]; then
        storeRematch=("${BASH_REMATCH[@]}")
        echo "${storeRematch[1]}; ${storeRematch[2]}"
        checkNum ${storeRematch[1]}
        checkNum ${storeRematch[2]}
    fi

}

checkNum ()
{
    if [[ $1 =~ [a-z]+([0-9]+)[A-Z]+([0-9]+)[a-z]+ ]]; then
        echo "${BASH_REMATCH[1]}; ${BASH_REMATCH[2]}"
    fi
}

set -x
checkABC $inputline

执行就像我想要的那样:

bash ./notleaking.sh
+ checkABC abc123ABC123abc,xyz890XYZ890xyz
+ local teststring=abc123ABC123abc,xyz890XYZ890xyz
+ local 'pattern=([^,]+),(.*)'
+ local -a storeRematch
+ [[ abc123ABC123abc,xyz890XYZ890xyz =~ ([^,]+),(.*) ]]
+ storeRematch=("${BASH_REMATCH[@]}")
+ echo 'abc123ABC123abc; xyz890XYZ890xyz'
abc123ABC123abc; xyz890XYZ890xyz
+ checkNum abc123ABC123abc
+ [[ abc123ABC123abc =~ [a-z]+([0-9]+)[A-Z]+([0-9]+)[a-z]+ ]]
+ echo '123; 123'
123; 123
+ checkNum xyz890XYZ890xyz
+ [[ xyz890XYZ890xyz =~ [a-z]+([0-9]+)[A-Z]+([0-9]+)[a-z]+ ]]
+ echo '890; 890'
890; 890

2 个答案:

答案 0 :(得分:1)

BASH_REMATCH是一个只读变量,因此local BASH_REMATCH之类的内容 不会起作用。

您建议自己选择将结果复制到另一个变量:

local re
re=("${BASH_REMATCH[@]}")

在你的情况下 - 只是提一下 - 你可以使用:

# teststring="1234,5678"
checkNum "${teststring%%,*}" # 1234
checkNum "${teststring#*,}"  # 5678

答案 1 :(得分:1)

有点破解,但由于它只是当前shell的本地,你可以在函数中运行子shell。

checkNum ()
{
(
    if [[ $1 =~ [a-z]+([0-9]+)[A-Z]+([0-9]+)[a-z]+ ]]; then
        echo "${BASH_REMATCH[1]}; ${BASH_REMATCH[2]}"
    fi
)
}

(
 checkNum ${BASH_REMATCH[1]}
 checkNum ${BASH_REMATCH[2]}
)

这将使BASH_REMATCH不会对两个函数都是全局的。

除此之外,我认为将它分配给另一个阵列是你将获得的最佳效果(因为它没有打开一个新的进程/子shell,因此比这更好)。