【问题标题】:Is anyone aware of the limitations in the gawk gsub function?有人知道 gawk gsub 函数的限制吗?
【发布时间】:2016-07-30 18:13:06
【问题描述】:

在将敏感值写入日志文件之前,我正在尝试在命令行中屏蔽键、令牌等敏感值。
例如:

MY_TOKEN='MaskThisPlease'
MY_CMD="my_command ${MY_TOKEN} SomeOtherString"
echo "${MY_CMD}" | gawk -v k="${MY_TOKEN}" -v m="XXXXXX" '{gsub(k,m);print}'

结果是:

my_command XXXXXX SomeOtherString

现在当 MY_TOKEN 包含特定字符时,屏蔽将不起作用和/或会产生错误。一些特殊字符是: $ ^ * ( ) + [ ] | \ ?

下面的工作正常

MY_TOKEN='MaskThisPlease_SomeABCs_Some123s_SomeOther//!!@@##%%_--==``~~{{}}::;;""<<>>,,..zzzzzzzzzzzzzzzzzzzzzzzzz'
MY_CMD="my_command ${MY_TOKEN} SomeOtherString"
echo "${MY_CMD}" | awk -v k="${MY_TOKEN}" -v m="XXXXXX" '{gsub(k,m);print}'

我试过 sed 但有分隔符限制,即当 '+' 在 MY_TOKEN

MY_TOKEN='MaskThisPlease_SomeABCs_Some123s_SomeOther+PlusSign+here'
MY_CMD="my_command ${MY_TOKEN} SomeOtherString"
echo "${MY_CMD}" | sed "s+${MY_TOKEN}+XXXXXX+g"

sed: -e expression #1, char 55: unknown option to `s'

所以,我的问题是

是否有另一种方法可以在不达到上述要求且没有大小限制的情况下执行屏蔽(MY_TOKEN 可能为 700 个字符)?

以下是后来添加的,以响应您的 cmets 和答案 1:
我刚加入 Stack Overflow,这是我的第一篇文章。我无法将我的测试数据附加为 r.dat。 r.dat 中的每一行都是我的令牌的值(有关详细信息,请参阅下面的答案 1)。

MaskThisPlease_SomeABCs_Some123s_SomeOther//!!@@##%%_--==``~~{{}}::;;""<<>>,,..zzzzzzzzzzzzzzzzzzzzzzzzz
AlphaNumericCharacters1234567890
''MaskThisPlease_SomeABCs_Some123s_SomeOther//!!@@##%%_--==``~~{{}}::;;""<<>>,,..zzzzzzzzzzzzzzzzzzzzzzzzz''
MaskThisPlease_SomeABCs_Some123s_SomeOther//!!@@##%%_--==``~~{{}}::;;""<<>>,,..$zzzzzzzzzzzzzzzzzzzzzzzzz
MaskThisPlease_SomeABCs_Some123s_SomeOther//!!@@##%%_--==``~~{{}}::;;""<<>>,,..$^zzzzzzzzzzzzzzzzzzzzzzzzz
MaskThisPlease_SomeABCs_Some123s_SomeOther//!!@@##%%_--==``~~{{}}::;;""<<>>,,..$^zzzzzzzzzzzzzzzzzzzzzzzzz
MaskThisPlease_SomeABCs_Some123s_SomeOther//!!@@##%%_--==``~~{{}}::;;""<<>>,,..$^(zzzzzzzzzzzzzzzzzzzzzzzzz
MaskThisPlease_SomeABCs_Some123s_SomeOther//!!@@##%%_--==``~~{{}}::;;""<<>>,,..$^()zzzzzzzzzzzzzzzzzzzzzzzzz
MaskThisPlease_SomeABCs_Some123s_SomeOther//!!@@##%%_--==``~~{{}}::;;""<<>>,,..$^()+zzzzzzzzzzzzzzzzzzzzzzzzz
MaskThisPlease_SomeABCs_Some123s_SomeOther//!!@@##%%_--==``~~{{}}::;;""<<>>,,..$^()+[zzzzzzzzzzzzzzzzzzzzzzzzz
MaskThisPlease_SomeABCs_Some123s_SomeOther//!!@@##%%_--==``~~{{}}::;;""<<>>,,..$^()+[]zzzzzzzzzzzzzzzzzzzzzzzzz
MaskThisPlease_SomeABCs_Some123s_SomeOther//!!@@##%%_--==``~~{{}}::;;""<<>>,,..$^()+[]|zzzzzzzzzzzzzzzzzzzzzzzzz
MaskThisPlease_SomeABCs_Some123s_SomeOther//!!@@##%%_--==``~~{{}}::;;""<<>>,,..$^()+[]|?zzzzzzzzzzzzzzzzzzzzzzzzz
MaskThisPlease_SomeABCs_Some123s_SomeOther//!!@@##%%_--==``~~{{}}::;;""<<>>,,..$^()+[]|?*zzzzzzzzzzzzzzzzzzzzzzzzz
MaskThisPlease_SomeABCs_Some123s_SomeOther//!!@@##%%_--==``~~{{}}::;;""<<>>,,..$^()+[]|?**zzzzzzzzzzzzzzzzzzzzzzzzz
MaskThisPlease_SomeABCs_Some123s_SomeOther//!!@@##%%_--==``~~{{}}::;;""<<>>,,..$^()+[]|?*)zzzzzzzzzzzzzzzzzzzzzzzzz
MaskThisPlease_SomeABCs_Some123s_SomeOther//!!@@##%%_--==``~~{{}}::;;""<<>>,,..$^()+[]|?*.zzzzzzzzzzzzzzzzzzzzzzzzz
MaskThisPlease_SomeABCs_Some123s_SomeOther//!!@@##%%_--==``~~{{}}::;;""<<>>,,..$^()+[]|?.*zzzzzzzzzzzzzzzzzzzzzzzzz
MaskThisPlease_SomeABCs_Some123s_SomeOther//!!@@##%%_--==``~~{{}}::;;""<<>>,,..$^()+[]|?*(zzzzzzzzzzzzzzzzzzzzzzzzz
MaskThisPlease_SomeABCs_Some123s_SomeOther//!!@@##%%_--==``~~{{}}::;;""<<>>,,..$^()+[]|?\\zzzzzzzzzzzzzzzzzzzzzzzzz
MaskThisPlease_SomeABCs_Some123s_SomeOther//!!@@##%%_--==``~~{{}}::;;""<<>>,,..$^()+[]|?\zzzzzzzzzzzzzzzzzzzzzzzzz

这是第一个代码 sn-p,它显示了 r.awk 和 bash 内置替换函数中的一些限制

clear
# Read one by one my test cases
I=0
cat ./r.dat | while IFS= read -r MY_TOKEN
do
    I=$((I+1))

    echo
    echo "#########################################################"
    echo "${I}) MyToken is ${MY_TOKEN}"
    echo "#########################################################"

    # Build my command including the value of my token
    MY_CMD="my_command ${MY_TOKEN} SomeOtherString"

    printf "Mask with gawk function: "
      echo "${MY_CMD}" | gawk -F'\n' -v k="${MY_TOKEN}" -v m="XXXXXX" -f ./r.awk 2>/dev/null

    printf "Mask with bash built-in: "
      echo "${MY_CMD/${MY_TOKEN}/XXXXXX}"
done

测试用例 19 表明 r.awk 比 bash 内置替换功能做得更好
测试用例 20 表明两者都失败了
测试用例 21 表明两者都失败了

这是第二个代码 sn-p,它显示了如何解决 r.awk 和 bash 内置替换函数中的问题

clear
# Read one by one my test cases
I=0
cat ./r.dat | while IFS= read -r MY_TOKEN
do
    I=$((I+1))

    # Escape RegEx characters
    MY_TOKEN_ESCAPED=$(echo ${MY_TOKEN} | sed 's:[][\/.^$*]:\\&:g')

    echo
    echo "#########################################################"
    echo "${I}) MyToken is ${MY_TOKEN}"
    echo "${I}) Escaped is ${MY_TOKEN_ESCAPED}"
    echo "#########################################################"

    # Build my command including the value of my token
    MY_CMD="my_command ${MY_TOKEN} SomeOtherString"

    printf "Mask with gawk function: "
      echo "${MY_CMD}" | gawk -F'\n' -v k="${MY_TOKEN_ESCAPED}" -v m="XXXXXX" -f ./r.awk 2>/dev/null

    printf "Mask with bash built-in: "
      echo "${MY_CMD/${MY_TOKEN_ESCAPED}/XXXXXX}"
done

可能有更好更简单的方法来处理它,那就是 100% POSIX....

【问题讨论】:

  • 忘了说,echo "${MY_CMD/${MY_TOKEN}/XXXXXX}" 工作正常,ShellCheck 没问题,但 checkbashisms 抱怨 (${parm/?/pat[/str] })。我只是想尽可能便携,希望你能帮忙:)
  • 另见stackoverflow.com/q/29613304/1745001。你想要一个正则表达式匹配吗?如果是这样,请在 awk 中使用 sed 或正则表达式操作。如果不是,并且您实际上想要字符串匹配,则将 awk 与字符串函数一起使用。 edit您的问题包括简洁、可测试的样本输入和预期输出,以便我们为您提供帮助。
  • 谢谢@EdMorton,我已经打包了一堆测试用例。我使用了来自 slicevinov 的 r.awk 并编写了两个代码 sn-ps 来演示导致问题的原因以及可以采取哪些措施来解决它。请参阅答案 1 中的详细信息。
  • 不要只说“它失败了”,告诉我们它是如何失败的,这样我们就不必尝试解决它。您的echo 本身可能正在解释字符(提示:请改用printf)。要了解有关您遇到的问题的更多信息,请参阅 unix.stackexchange.com/questions/169716/…stackoverflow.com/questions/29613304/…,并阅读 Arnold Robbins 的《Effective Awk Programming, 4th Edition》和 Chris Johnson 的《Shell Scripting Recipes》。

标签: awk sed gawk


【解决方案1】:

您可以使用indexits second argument 是字符串而不是正则表达式)并从文件中读取密钥。这是一个例子。创建四个文件:

r.awk

BEGIN {
    getline k < kfile; close(kfile)
    n = length(k)
}

function process(rst,   i, pre, ans) {
    while (i=index(rst, k)) {
        pre = substr(rst, 1,  i-1)
        rst = substr(rst, i + n)
        ans = ans pre m
    }
    return ans rst
}

{
    print process($0)
}

r.sh

awk -v kfile=r.key -v m=XXX  -f r.awk r.dat

r.dat

test\t\tMaskThisPlease_SomeABCs_Some123s_SomeOther//!!@@##%%_--==``~~{{}}::;;""<<>>,,..zzzzzzzzzzzzzzzzzzzzzzzzztest

r.key

\t\tMaskThisPlease_SomeABCs_Some123s_SomeOther//!!@@##%%_--==``~~{{}}::;;""<<>>,,..zzzzzzzzzzzzzzzzzzzzzzzzz

运行它 sh r.sh

预期输出:

testXXXtest

【讨论】:

  • @RobertoG。你能绕过一个shell变量吗?查看更新的答案。
  • 是的,我想就是这样,我将在新答案中发布详细信息。
【解决方案2】:

看起来这就是你想要做的:

$ cat tst.sh
while IFS= read -r my_token
do
    old_my_cmd="my_command $my_token SomeOtherString"

    new_my_cmd=$(
        printf '%s\n' "$old_my_cmd" |
        awk -v m='XXXXXX' '
            BEGIN {
                my_token=ARGV[1]; ARGV[1]=""; ARGC--
                lgth = length(my_token)
            }
            {
                while ( start = index($0,my_token) ) {
                    printf "%s%s", substr($0,1,start-1), m
                    $0 = substr($0,start+lgth)
                }
                print
            }
        ' "$my_token"
    )

    printf 'old_my_cmd="%s"\n' "$old_my_cmd"
    printf 'new_my_cmd="%s"\n' "$new_my_cmd"
    printf "\n"

done < r.dat

.

$ ./tst.sh
old_my_cmd="my_command MaskThisPlease_SomeABCs_Some123s_SomeOther//!!@@##%%_--==``~~{{}}::;;""<<>>,,..zzzzzzzzzzzzzzzzzzzzzzzzz SomeOtherString"
new_my_cmd="my_command XXXXXX SomeOtherString"

old_my_cmd="my_command AlphaNumericCharacters1234567890 SomeOtherString"
new_my_cmd="my_command XXXXXX SomeOtherString"

old_my_cmd="my_command ''MaskThisPlease_SomeABCs_Some123s_SomeOther//!!@@##%%_--==``~~{{}}::;;""<<>>,,..zzzzzzzzzzzzzzzzzzzzzzzzz'' SomeOtherString"
new_my_cmd="my_command XXXXXX SomeOtherString"

old_my_cmd="my_command MaskThisPlease_SomeABCs_Some123s_SomeOther//!!@@##%%_--==``~~{{}}::;;""<<>>,,..$zzzzzzzzzzzzzzzzzzzzzzzzz SomeOtherString"
new_my_cmd="my_command XXXXXX SomeOtherString"

old_my_cmd="my_command MaskThisPlease_SomeABCs_Some123s_SomeOther//!!@@##%%_--==``~~{{}}::;;""<<>>,,..$^zzzzzzzzzzzzzzzzzzzzzzzzz SomeOtherString"
new_my_cmd="my_command XXXXXX SomeOtherString"

old_my_cmd="my_command MaskThisPlease_SomeABCs_Some123s_SomeOther//!!@@##%%_--==``~~{{}}::;;""<<>>,,..$^zzzzzzzzzzzzzzzzzzzzzzzzz SomeOtherString"
new_my_cmd="my_command XXXXXX SomeOtherString"

old_my_cmd="my_command MaskThisPlease_SomeABCs_Some123s_SomeOther//!!@@##%%_--==``~~{{}}::;;""<<>>,,..$^(zzzzzzzzzzzzzzzzzzzzzzzzz SomeOtherString"
new_my_cmd="my_command XXXXXX SomeOtherString"

old_my_cmd="my_command MaskThisPlease_SomeABCs_Some123s_SomeOther//!!@@##%%_--==``~~{{}}::;;""<<>>,,..$^()zzzzzzzzzzzzzzzzzzzzzzzzz SomeOtherString"
new_my_cmd="my_command XXXXXX SomeOtherString"

old_my_cmd="my_command MaskThisPlease_SomeABCs_Some123s_SomeOther//!!@@##%%_--==``~~{{}}::;;""<<>>,,..$^()+zzzzzzzzzzzzzzzzzzzzzzzzz SomeOtherString"
new_my_cmd="my_command XXXXXX SomeOtherString"

old_my_cmd="my_command MaskThisPlease_SomeABCs_Some123s_SomeOther//!!@@##%%_--==``~~{{}}::;;""<<>>,,..$^()+[zzzzzzzzzzzzzzzzzzzzzzzzz SomeOtherString"
new_my_cmd="my_command XXXXXX SomeOtherString"

old_my_cmd="my_command MaskThisPlease_SomeABCs_Some123s_SomeOther//!!@@##%%_--==``~~{{}}::;;""<<>>,,..$^()+[]zzzzzzzzzzzzzzzzzzzzzzzzz SomeOtherString"
new_my_cmd="my_command XXXXXX SomeOtherString"

old_my_cmd="my_command MaskThisPlease_SomeABCs_Some123s_SomeOther//!!@@##%%_--==``~~{{}}::;;""<<>>,,..$^()+[]|zzzzzzzzzzzzzzzzzzzzzzzzz SomeOtherString"
new_my_cmd="my_command XXXXXX SomeOtherString"

old_my_cmd="my_command MaskThisPlease_SomeABCs_Some123s_SomeOther//!!@@##%%_--==``~~{{}}::;;""<<>>,,..$^()+[]|?zzzzzzzzzzzzzzzzzzzzzzzzz SomeOtherString"
new_my_cmd="my_command XXXXXX SomeOtherString"

old_my_cmd="my_command MaskThisPlease_SomeABCs_Some123s_SomeOther//!!@@##%%_--==``~~{{}}::;;""<<>>,,..$^()+[]|?*zzzzzzzzzzzzzzzzzzzzzzzzz SomeOtherString"
new_my_cmd="my_command XXXXXX SomeOtherString"

old_my_cmd="my_command MaskThisPlease_SomeABCs_Some123s_SomeOther//!!@@##%%_--==``~~{{}}::;;""<<>>,,..$^()+[]|?**zzzzzzzzzzzzzzzzzzzzzzzzz SomeOtherString"
new_my_cmd="my_command XXXXXX SomeOtherString"

old_my_cmd="my_command MaskThisPlease_SomeABCs_Some123s_SomeOther//!!@@##%%_--==``~~{{}}::;;""<<>>,,..$^()+[]|?*)zzzzzzzzzzzzzzzzzzzzzzzzz SomeOtherString"
new_my_cmd="my_command XXXXXX SomeOtherString"

old_my_cmd="my_command MaskThisPlease_SomeABCs_Some123s_SomeOther//!!@@##%%_--==``~~{{}}::;;""<<>>,,..$^()+[]|?*.zzzzzzzzzzzzzzzzzzzzzzzzz SomeOtherString"
new_my_cmd="my_command XXXXXX SomeOtherString"

old_my_cmd="my_command MaskThisPlease_SomeABCs_Some123s_SomeOther//!!@@##%%_--==``~~{{}}::;;""<<>>,,..$^()+[]|?.*zzzzzzzzzzzzzzzzzzzzzzzzz SomeOtherString"
new_my_cmd="my_command XXXXXX SomeOtherString"

old_my_cmd="my_command MaskThisPlease_SomeABCs_Some123s_SomeOther//!!@@##%%_--==``~~{{}}::;;""<<>>,,..$^()+[]|?*(zzzzzzzzzzzzzzzzzzzzzzzzz SomeOtherString"
new_my_cmd="my_command XXXXXX SomeOtherString"

old_my_cmd="my_command MaskThisPlease_SomeABCs_Some123s_SomeOther//!!@@##%%_--==``~~{{}}::;;""<<>>,,..$^()+[]|?\\zzzzzzzzzzzzzzzzzzzzzzzzz SomeOtherString"
new_my_cmd="my_command XXXXXX SomeOtherString"

old_my_cmd="my_command MaskThisPlease_SomeABCs_Some123s_SomeOther//!!@@##%%_--==``~~{{}}::;;""<<>>,,..$^()+[]|?\zzzzzzzzzzzzzzzzzzzzzzzzz SomeOtherString"
new_my_cmd="my_command XXXXXX SomeOtherString"

【讨论】:

    【解决方案3】:

    这是第三个代码 sn-p 将@EdMorton 的方法结合到我的原始代码中

    # Read one by one my test cases
    I=0
    cat ./r.dat | while IFS= read -r MY_TOKEN
    do
        I=$((I+1))
    
        echo
        echo "#########################################################"
        printf '%s) MyToken is %s\n' "${I}" "${MY_TOKEN}"
        echo "#########################################################"
    
        # Build my command including the value of my token
        MY_CMD="my_command ${MY_TOKEN} SomeOtherString"
    
        MY_CMD_MASKED=$(
            printf '%s\n' "${MY_CMD}" |
            awk -v m='XXXXXX' '
                BEGIN {
                    my_token=ARGV[1]; ARGV[1]=""; ARGC--
                    lgth = length(my_token)
                }
                {
                    while ( start = index($0,my_token) ) {
                        printf "%s%s", substr($0,1,start-1), m
                        $0 = substr($0,start+lgth)
                    }
                    print
                }
            ' "${MY_TOKEN}"
        )
    
        printf 'Mask with gawk function: %s\n' "${MY_CMD_MASKED}"
        printf 'Mask with bash built-in: %s\n' "${MY_CMD/${MY_TOKEN}/XXXXXX}"
    done
    

    以下是我们之前讨论过的测试用例 19、20 和 21 的结果:

    #########################################################
    19) MyToken is MaskThisPlease_SomeABCs_Some123s_SomeOther//!!@@##%%_--==``~~{{}}::;;""<<>>,,..$^()+[]|?*(zzzzzzzzzzzzzzzzzzzzzzzzz
    #########################################################
    Mask with gawk function: my_command XXXXXX SomeOtherString
    Mask with bash built-in: my_command XXXXXX SomeOtherString
    
    #########################################################
    20) MyToken is MaskThisPlease_SomeABCs_Some123s_SomeOther//!!@@##%%_--==``~~{{}}::;;""<<>>,,..$^()+[]|?\\zzzzzzzzzzzzzzzzzzzzzzzzz
    #########################################################
    Mask with gawk function: my_command XXXXXX SomeOtherString
    Mask with bash built-in: my_command MaskThisPlease_SomeABCs_Some123s_SomeOther//!!@@##%%_--==``~~{{}}::;;""<<>>,,..$^()+[]|?\\zzzzzzzzzzzzzzzzzzzzzzzzz SomeOtherString
    
    #########################################################
    21) MyToken is MaskThisPlease_SomeABCs_Some123s_SomeOther//!!@@##%%_--==``~~{{}}::;;""<<>>,,..$^()+[]|?\zzzzzzzzzzzzzzzzzzzzzzzzz
    #########################################################
    Mask with gawk function: my_command XXXXXX SomeOtherString
    Mask with bash built-in: my_command MaskThisPlease_SomeABCs_Some123s_SomeOther//!!@@##%%_--==``~~{{}}::;;""<<>>,,..$^()+[]|?\zzzzzzzzzzzzzzzzzzzzzzzzz SomeOtherString
    

    从上述脚本中删除以下行时,它会通过“checkbashisms -fx”以及http://www.shellcheck.net/

    printf 'Mask with bash built-in: %s\n' "${MY_CMD/${MY_TOKEN}/XXXXXX}"
    

    上面的代码只是为了展示这两种方法之间的差异。
    感谢大家的快速反馈,并帮助我改善了这篇文章中的沟通。

    【讨论】:

    • 不要将其他人的答案复制/粘贴到您自己的答案中。见stackoverflow.com/help/someone-answers。此外,不要按照约定对非导出的变量名使用全部大写,以避免与现有变量名和谷歌 UUOC 冲突,然后修复它。就用我写的吧。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-03
    • 2011-03-31
    • 1970-01-01
    • 2011-06-16
    • 1970-01-01
    • 2010-10-18
    相关资源
    最近更新 更多