使用 gsub 将一个变量替换为另一个来自函数调用的值的变量

发布于 2025-01-10 18:09:22 字数 4161 浏览 0 评论 0原文

我有一个函数可以用文件中的某些模式替换实际值。我在这里试图实现的目标是调用一个使用 gsub 的函数来查找和替换字符串,替换值基本上来自另一个函数调用。

$ cat pat-file
name         10101010
phone        10101010
code         10101010
bankaccount  1010101010101

$ cat data_sub.sh

abc()
{
awk '
function mask(str, str_masked) {
    for (j=1; j<=length(str); j++) {
        if (substr(masks[i], j, 1)==1) {
            c = substr(str, j, 1)
        } else {
            c = "*"
        }

        str_masked = str_masked c
    }

    return str_masked
}

FNR == NR {
    tags[NR-1] = $1
    masks[NR-1] = $2
}

FNR != NR {
    line = $0

    for (i in tags) {
        regex = "<"tags[i]">[^<]+</"tags[i]">"
        masked_line = ""
        l = length(tags[i])
        while (match(line, regex) > 0) {
            fulltag = substr(line, RSTART, RLENGTH)
            tagval = substr(fulltag, l+3, RLENGTH-l-l-5)
            fulltag_masked = "<"tags[i]">" mask(tagval) "</"tags[i]">"
            masked_line = masked_line substr(line, 1, RSTART-1) fulltag_masked

            line = substr(line, RSTART + RLENGTH)
        }

        line = masked_line line
    }

    print line
}' "$@" pat-file file-1 > output_file
}

abc

tagval 变量存储 XML 标记的值,该标记在 XML 内部被屏蔽,但由于它也存在于 XML 外部,因此我也需要屏蔽这些值。请参阅输入文件

file-1

This is a demo data = ABCD
This is a demo data = XYCD
This is a demo data = ABCD
This is a demo data = BLAH
This is a demo data = ABCD
This is a demo data = MEH
This is a demo data = ABCD
This is a demo data = ABCD
This is a demo data = ABCD
This is a demo data = ABCD and MEH
This is a demo data <tag changed="yes"<name>ABCD</name><phone>98762123</phone><code>MEH</code><bankaccount>4563728495847</bankaccount></tag>
This is a demo data <tag changed="yes"<name>ABCD</name><phone>98762123</phone><code>MEH</code><bankaccount>4563728495847</bankaccount></tag>
This is a demo data <tag changed="yes"<name>ABCD</name><phone>98762123</phone><code>MEH</code><bankaccount>4563728495847</bankaccount></tag>

逻辑非常简单且非常直接,即存储所有提取的被屏蔽的标记值,然后对这些值(但在 XML 之外)执行相同的屏蔽算法。我怎样才能实现这个目标?

输出文件

This is a demo data = ABCD
This is a demo data = XYCD
This is a demo data = ABCD
This is a demo data = BLAH
This is a demo data = ABCD
This is a demo data = MEH
This is a demo data = ABCD
This is a demo data = ABCD
This is a demo data = ABCD
This is a demo data = ABCD and MEH
This is a demo data <tag changed="yes"<name>A*C*</name><phone>9*7*2*2*</phone><code>M*H</code><bankaccount>4*6*7*8*9*8*7</bankaccount></tag>
This is a demo data <tag changed="yes"<name>A*C*</name><phone>9*7*2*2*</phone><code>M*H</code><bankaccount>4*6*7*8*9*8*7</bankaccount></tag>
This is a demo data <tag changed="yes"<name>A*C*</name><phone>9*7*2*2*</phone><code>M*H</code><bankaccount>4*6*7*8*9*8*7</bankaccount></tag>

预期输出文件

This is a demo data = A*C*
This is a demo data = XYCD
This is a demo data = A*C*
This is a demo data = BLAH
This is a demo data = A*C*
This is a demo data = M*H
This is a demo data = A*C*
This is a demo data = A*C*
This is a demo data = A*C*
This is a demo data = A*C* and M*H
This is a demo data <tag changed="yes"<name>A*C*</name><phone>9*7*2*2*</phone><code>M*H</code><bankaccount>4*6*7*8*9*8*7</bankaccount></tag>
This is a demo data <tag changed="yes"<name>A*C*</name><phone>9*7*2*2*</phone><code>M*H</code><bankaccount>4*6*7*8*9*8*7</bankaccount></tag>
This is a demo data <tag changed="yes"<name>A*C*</name><phone>9*7*2*2*</phone><code>M*H</code><bankaccount>4*6*7*8*9*8*7</bankaccount></tag>

I have a function which substitutes actual values with some pattern from a file. The objective I'm trying to achieve here is to call a function which uses gsub to find and replace the string in a way that the substitution value is basically coming from another function call.

$ cat pat-file
name         10101010
phone        10101010
code         10101010
bankaccount  1010101010101

$ cat data_sub.sh

abc()
{
awk '
function mask(str, str_masked) {
    for (j=1; j<=length(str); j++) {
        if (substr(masks[i], j, 1)==1) {
            c = substr(str, j, 1)
        } else {
            c = "*"
        }

        str_masked = str_masked c
    }

    return str_masked
}

FNR == NR {
    tags[NR-1] = $1
    masks[NR-1] = $2
}

FNR != NR {
    line = $0

    for (i in tags) {
        regex = "<"tags[i]">[^<]+</"tags[i]">"
        masked_line = ""
        l = length(tags[i])
        while (match(line, regex) > 0) {
            fulltag = substr(line, RSTART, RLENGTH)
            tagval = substr(fulltag, l+3, RLENGTH-l-l-5)
            fulltag_masked = "<"tags[i]">" mask(tagval) "</"tags[i]">"
            masked_line = masked_line substr(line, 1, RSTART-1) fulltag_masked

            line = substr(line, RSTART + RLENGTH)
        }

        line = masked_line line
    }

    print line
}' "$@" pat-file file-1 > output_file
}

abc

The tagval variable stores the value of the XML tag which gets masked inside the XML but as it is present outside the XML as well, I need to mask those values too. See the input file

file-1

This is a demo data = ABCD
This is a demo data = XYCD
This is a demo data = ABCD
This is a demo data = BLAH
This is a demo data = ABCD
This is a demo data = MEH
This is a demo data = ABCD
This is a demo data = ABCD
This is a demo data = ABCD
This is a demo data = ABCD and MEH
This is a demo data <tag changed="yes"<name>ABCD</name><phone>98762123</phone><code>MEH</code><bankaccount>4563728495847</bankaccount></tag>
This is a demo data <tag changed="yes"<name>ABCD</name><phone>98762123</phone><code>MEH</code><bankaccount>4563728495847</bankaccount></tag>
This is a demo data <tag changed="yes"<name>ABCD</name><phone>98762123</phone><code>MEH</code><bankaccount>4563728495847</bankaccount></tag>

The logic is simple and pretty straight forward i.e store all the extracted tag value that get masked, then perform the same masking algorithm on those values but outside XML. How can I achieve this?

Output file

This is a demo data = ABCD
This is a demo data = XYCD
This is a demo data = ABCD
This is a demo data = BLAH
This is a demo data = ABCD
This is a demo data = MEH
This is a demo data = ABCD
This is a demo data = ABCD
This is a demo data = ABCD
This is a demo data = ABCD and MEH
This is a demo data <tag changed="yes"<name>A*C*</name><phone>9*7*2*2*</phone><code>M*H</code><bankaccount>4*6*7*8*9*8*7</bankaccount></tag>
This is a demo data <tag changed="yes"<name>A*C*</name><phone>9*7*2*2*</phone><code>M*H</code><bankaccount>4*6*7*8*9*8*7</bankaccount></tag>
This is a demo data <tag changed="yes"<name>A*C*</name><phone>9*7*2*2*</phone><code>M*H</code><bankaccount>4*6*7*8*9*8*7</bankaccount></tag>

Expected Output file

This is a demo data = A*C*
This is a demo data = XYCD
This is a demo data = A*C*
This is a demo data = BLAH
This is a demo data = A*C*
This is a demo data = M*H
This is a demo data = A*C*
This is a demo data = A*C*
This is a demo data = A*C*
This is a demo data = A*C* and M*H
This is a demo data <tag changed="yes"<name>A*C*</name><phone>9*7*2*2*</phone><code>M*H</code><bankaccount>4*6*7*8*9*8*7</bankaccount></tag>
This is a demo data <tag changed="yes"<name>A*C*</name><phone>9*7*2*2*</phone><code>M*H</code><bankaccount>4*6*7*8*9*8*7</bankaccount></tag>
This is a demo data <tag changed="yes"<name>A*C*</name><phone>9*7*2*2*</phone><code>M*H</code><bankaccount>4*6*7*8*9*8*7</bankaccount></tag>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

南薇 2025-01-17 18:09:22

假设:

  • 如果一个字符串出现在不同的标签下(例如,name=ABCDcode=ABCD),则 awk 找到的第一个掩码将用于屏蔽字符串(即,我们不会优先处理标记/掩码对的顺序)
  • 字符串(要屏蔽的)可以显示在一行中的任何位置,
  • 当匹配非标记子字符串时, 我们将使用 < code>awk 字边界(例如,当屏蔽 ABCD 时,我们也会屏蔽 ABCD-XYZ,但不会屏蔽 ABCDABCDABCD_XYZ >)
  • 这两个文件以及值/掩码值对数组将适合内存
  • 如果 OP 提供掩码 111111111... (全部为 1),则 会去提前并执行(有效)无操作操作

一般操作:

  • 处理输入文件(例如,file-1),查找“标签”条目,
  • 如果我们找到任何匹配的“标签”条目,我们将应用建议的掩码到
  • 每个被掩码的值的相应值我们将在一个新数组中保留所述值及其掩码的副本
  • 以用于重复值我们将应用保存的掩码
  • 所有行,无论有或没有标签/掩码-data,保存在数组
  • END 中处理再次运行我们的行数组,查找以前屏蔽的任何(字边界)字符串,如果找到,则
  • 在掩码为 11111111... 的情况下 替换为保存的掩码值(所有 1's)此 END 处理也将重新屏蔽“标记”条目(仍然有效,无操作)
  • 所有行都将发送到

stdout示例输入文件的一些行:

$ cat file-1
This is a demo data = ABCD
This is a demo data = XYCD
This is a demo data = ABCD
This is a demo data = BLAH
This is a demo data = ABCD
This is a demo data = MEH
This is a demo data = ABCD
This is a demo data = ABCD
This is a demo data = ABCD
This is a demo data = ABCD and MEH
This is a demo data <tag changed="yes"<name>ABCD</name><phone>98762123</phone><code>MEH</code><bankaccount>4563728495847</bankaccount></tag>
This is a demo data <tag changed="yes"<name>ABCD</name><phone>98762123</phone><code>MEH</code><bankaccount>4563728495847</bankaccount></tag>
This is a demo data <tag changed="yes"<name>ABCD</name><phone>98762123</phone><code>MEH</code><bankaccount>4563728495847</bankaccount></tag>
#####################
# some more lines ...
#####################
This is a demo data = ABCD and XYCD
This is a demo data = XYCD and MEH
This is ABCD and MEH demo data <tag changed="yes"<name>Winkelstein</name><phone>98762123</phone><code>MEH</code><bankaccount>4563728495847</bankaccount></tag>
One last line ABCD ABCD-XYZ ABCDABCD ABCD_XYZ

一想法建立在OP当前的awk代码上:

awk '
function mask(str, str_masked) {
    for (j=1; j<=length(str); j++) {
        if (substr(masks[tag], j, 1) == 1)
           c = substr(str, j, 1)
        else
           c = "*"
        str_masked = str_masked c
    }
    return str_masked
}

FNR == NR { masks[$1] = $2; next }
          { line = $0

            for (tag in masks) {
                regex = "<" tag ">[^<]+</" tag ">"
                masked_line = ""
                len = length(tag)

                while (match(line, regex) > 0) {
                      val = substr(line, RSTART+(len+2), RLENGTH-(len+2)-(len+3))
                      masked[val]= (val in masked) ? masked[val] : mask(val)
                      masked_line = masked_line substr(line, 1, RSTART-1) "<" tag ">" masked[val] "</" tag ">"
                      line = substr(line, RSTART + RLENGTH)
                }
                line = masked_line line
            }
            lines[FNR]=line
        }

END     { for (i=1;i<=FNR;i++) {
              for (val in masked) {
                  regex="\\<" val "\\>"
                  gsub(regex,masked[val],lines[i])
              }
              print lines[i]
          }
        }
' pat-file file-1

这会生成:

This is a demo data = A*C*
This is a demo data = XYCD
This is a demo data = A*C*
This is a demo data = BLAH
This is a demo data = A*C*
This is a demo data = M*H
This is a demo data = A*C*
This is a demo data = A*C*
This is a demo data = A*C*
This is a demo data = A*C* and M*H
This is a demo data <tag changed="yes"<name>A*C*</name><phone>9*7*2*2*</phone><code>M*H</code><bankaccount>4*6*7*8*9*8*7</bankaccount></tag>
This is a demo data <tag changed="yes"<name>A*C*</name><phone>9*7*2*2*</phone><code>M*H</code><bankaccount>4*6*7*8*9*8*7</bankaccount></tag>
This is a demo data <tag changed="yes"<name>A*C*</name><phone>9*7*2*2*</phone><code>M*H</code><bankaccount>4*6*7*8*9*8*7</bankaccount></tag>
#####################
# some more lines ...
#####################
This is a demo data = A*C* and XYCD
This is a demo data = XYCD and M*H
This is A*C* and M*H demo data <tag changed="yes"<name>W*n*e*s****</name><phone>9*7*2*2*</phone><code>M*H</code><bankaccount>4*6*7*8*9*8*7</bankaccount></tag>
One last line A*C* A*C*-XYZ ABCDABCD ABCD_XYZ

Assumptions:

  • if a string shows up under different tags (eg, name=ABCD and code=ABCD) then the 1st mask found by awk will be used to mask the string (ie, we won't prioritize the order in which tag/mask pairs are processed)
  • strings (to be masked) could show up anywhere in a line
  • when matching for non-tag substrings we'll use awk word boundaries (eg, when masking ABCD we'll also mask ABCD-XYZ but we won't mask ABCDABCD nor ABCD_XYZ)
  • both files, along with an array of value/masked-value pairs, will fit in memory
  • if OP provides a mask of 111111111... (all 1's) we'll go ahead and perform the (effective) no-op operation

General operation:

  • process input file (eg, file-1) looking for 'tag' entries
  • if we find any matching 'tag' entries we'll apply the proposed mask to the corresponding value
  • for each value that is masked we'll keep a copy of said value, and its mask, in a new array
  • for repeat values we'll apply the saved mask
  • all lines, with or without tags/masked-data, are saved in an array
  • END processing runs through our array of lines again, looking for any (word-boundaried) strings that were previously masked and if found, replace with the saved mask value
  • in the case of a mask of 11111111... (all 1's) this END processing will re-mask the 'tag' entries, too (still, effectively, a no-op)
  • all lines are then sent to stdout

Adding some lines to the sample input file:

$ cat file-1
This is a demo data = ABCD
This is a demo data = XYCD
This is a demo data = ABCD
This is a demo data = BLAH
This is a demo data = ABCD
This is a demo data = MEH
This is a demo data = ABCD
This is a demo data = ABCD
This is a demo data = ABCD
This is a demo data = ABCD and MEH
This is a demo data <tag changed="yes"<name>ABCD</name><phone>98762123</phone><code>MEH</code><bankaccount>4563728495847</bankaccount></tag>
This is a demo data <tag changed="yes"<name>ABCD</name><phone>98762123</phone><code>MEH</code><bankaccount>4563728495847</bankaccount></tag>
This is a demo data <tag changed="yes"<name>ABCD</name><phone>98762123</phone><code>MEH</code><bankaccount>4563728495847</bankaccount></tag>
#####################
# some more lines ...
#####################
This is a demo data = ABCD and XYCD
This is a demo data = XYCD and MEH
This is ABCD and MEH demo data <tag changed="yes"<name>Winkelstein</name><phone>98762123</phone><code>MEH</code><bankaccount>4563728495847</bankaccount></tag>
One last line ABCD ABCD-XYZ ABCDABCD ABCD_XYZ

One idea building on OP's current awk code:

awk '
function mask(str, str_masked) {
    for (j=1; j<=length(str); j++) {
        if (substr(masks[tag], j, 1) == 1)
           c = substr(str, j, 1)
        else
           c = "*"
        str_masked = str_masked c
    }
    return str_masked
}

FNR == NR { masks[$1] = $2; next }
          { line = $0

            for (tag in masks) {
                regex = "<" tag ">[^<]+</" tag ">"
                masked_line = ""
                len = length(tag)

                while (match(line, regex) > 0) {
                      val = substr(line, RSTART+(len+2), RLENGTH-(len+2)-(len+3))
                      masked[val]= (val in masked) ? masked[val] : mask(val)
                      masked_line = masked_line substr(line, 1, RSTART-1) "<" tag ">" masked[val] "</" tag ">"
                      line = substr(line, RSTART + RLENGTH)
                }
                line = masked_line line
            }
            lines[FNR]=line
        }

END     { for (i=1;i<=FNR;i++) {
              for (val in masked) {
                  regex="\\<" val "\\>"
                  gsub(regex,masked[val],lines[i])
              }
              print lines[i]
          }
        }
' pat-file file-1

This generates:

This is a demo data = A*C*
This is a demo data = XYCD
This is a demo data = A*C*
This is a demo data = BLAH
This is a demo data = A*C*
This is a demo data = M*H
This is a demo data = A*C*
This is a demo data = A*C*
This is a demo data = A*C*
This is a demo data = A*C* and M*H
This is a demo data <tag changed="yes"<name>A*C*</name><phone>9*7*2*2*</phone><code>M*H</code><bankaccount>4*6*7*8*9*8*7</bankaccount></tag>
This is a demo data <tag changed="yes"<name>A*C*</name><phone>9*7*2*2*</phone><code>M*H</code><bankaccount>4*6*7*8*9*8*7</bankaccount></tag>
This is a demo data <tag changed="yes"<name>A*C*</name><phone>9*7*2*2*</phone><code>M*H</code><bankaccount>4*6*7*8*9*8*7</bankaccount></tag>
#####################
# some more lines ...
#####################
This is a demo data = A*C* and XYCD
This is a demo data = XYCD and M*H
This is A*C* and M*H demo data <tag changed="yes"<name>W*n*e*s****</name><phone>9*7*2*2*</phone><code>M*H</code><bankaccount>4*6*7*8*9*8*7</bankaccount></tag>
One last line A*C* A*C*-XYZ ABCDABCD ABCD_XYZ
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文