【问题标题】:Bash one-liner to mask data in filebash one-liner 来屏蔽文件中的数据
【发布时间】:2014-02-07 20:36:37
【问题描述】:

我有一个很大的文件。我需要屏蔽特定位置和特定记录类型中的所有字符。我到处搜索,但找不到这个非常简单的任务的解决方案。这是一个例子

文件名:hello.txt

文件:

0120140206INPUT FILE
1032682842 MR SIMPSON
20231458 742 Evergreen Terrace
3034560817 GREEN
1032682842 MR GRIFFIN
20231458 Spooner Street
3034560817 RED
3001 

我想做的是屏蔽以“10”开头的所有行的位置 12-16。像这样:

0120140206INPUT FILE
1032682842 XXXXXMPSON
20231458 742 Evergreen Terrace
3034560817 GREEN
1032682842 XXXXXIFFIN
20231458 Spooner Street
3034560817 RED
3001

【问题讨论】:

    标签: bash sed awk


    【解决方案1】:

    使用 sed

    sed -r '/^10/ s/^(.{11}).{5}/\1XXXXX/' file
    
    0120140206INPUT FILE
    1032682842 XXXXXMPSON
    20231458 742 Evergreen Terrace
    3034560817 GREEN
    1032682842 XXXXXIFFIN
    20231458 Spooner Street
    3034560817 RED
    3001
    

    说明

    • -r sed 中的有用选项,--regexp-extended
    • /^10/ 搜索以 10 开头的行。
    • s/^(.{11}).{5}/\1XXXXX/ 掩码位置 12-16 到 XXXXX

    同样的想法,如果你的awk是gawk,并且支持gensub()函数:

    awk '{$0=gensub(/^(10.{9}).{5}/,"\\1XXXXX",$0)}1' file
    

    更新:@tripleee 提供一个更短的:

    sed -r 's/^(10.{9}).{5}/\1XXXXX/' file
    

    【讨论】:

    • 或者只是sed -r 's/^(10.{9}).{5}/\1XXXXX/' hello.txt
    【解决方案2】:

    这可以是一种方式:

    $ awk 'BEGIN{FS=OFS=""} $1$2=="10" {for(i=12;i<=16;i++) $i="X"}1' file
    0120140206INPUT FILE
    1032682842 XXXXXMPSON
    20231458 742 Evergreen Terrace
    3034560817 GREEN
    1032682842 XXXXXIFFIN
    20231458 Spooner Street
    3034560817 RED
    3001
    

    说明

    • BEGIN{FS=OFS=""} 将字段分隔符设置为“”,这样第一个字符将是第一个字段,第二个字符将是第二个字段...
    • $1$2=="10" {for(i=12;i&lt;=16;i++) $i="X"}如果第一个字符是1,第二个字符是0,则从第12个到第16个字符更改为X
    • 1 true 条件,被评估为默认的 awk 行为:{print $0}

    【讨论】:

    • 可以将$1$2=="10"替换成/^10/
    • 很高兴看到这一点,@user1297532 !由于您是新来的,如果您的问题已经解决,请不要忘记将答案标记为已接受。您可以单击答案旁边的复选标记将其从空心切换为绿色。如有任何疑问,请参阅Help Center > Asking
    【解决方案3】:

    这个 awk 可以工作:

    awk '/^10/{q=substr($0, 12, 4); gsub(/./, "*", q); $0=substr($0, 1, 11) q substr($0, 17)}1' file
    

    【讨论】:

    • 这掩盖了很多,给像1032682842 **********这样的行,而不仅仅是1032682842 *****MPSON
    • 谢谢,我刚取了开始位置,忘记了结束位置。现已修复。
    【解决方案4】:

    应该这样做:

    awk '/^10/{q=substr($0,1,11);r=substr($0,17); $0=q "XXXXX" r }1' file
    0120140206INPUT FILE
    1032682842 XXXXXMPSON
    20231458 742 Evergreen Terrace
    3034560817 GREEN
    1032682842 XXXXXIFFIN
    20231458 Spooner Street
    3034560817 RED
    3001
    

    【讨论】:

      【解决方案5】:

      这可能对你有用(GNU sed):

      sed -r '/^10/{s/^(.{0,11})(.{0,5})/\1\n\2\n/;h;s/[^\n]/X/g;G;s/.*\n(.*)\n.*\n(.*)\n.*\n/\2\1/}' file
      

      对于以10 开头的行:在预期掩码的两侧放置两个标记,复制,用掩码字符替换除标记之外的所有字符,附加副本并操作标记之间的文本以定位掩码。

      注意这适合短线,不会引入人工制品。

      【讨论】:

        【解决方案6】:

        可以使用gawk定宽数据读取能力:

        gawk -v FIELDWIDTHS="11 5 9999" -v OFS="" '/^10/ { $2 = "XXXXX" } ; { print }' file
        

        https://www.gnu.org/software/gawk/manual/gawk.html#Constant-Size

        【讨论】:

          【解决方案7】:

          你可以使用 BASH:

          while read f1 f2; do
              if [[ $f1 =~ ^10 ]]; then
                      f2="XXXXX${f2:5}"
              fi
              echo $f1 $f2
          done < hello.txt
          

          如果您只需将第二个字段的前 5 个字符替换为 XXXXX,这将起作用。

          如果您需要将第 12 到第 16 个字符替换为 XXXXX 而不管字段如何,您可以做得更长:

          while read l; do
              if [[ $l =~ ^10 ]]; then
                      b=${l:11}
                      e=${l:16}
                      t=${b/$e/}
                      l=${l/$t/XXXXX}
              fi
              echo $l
          done < hello.txt
          

          【讨论】:

            【解决方案8】:

            perl 替代方案

            perl -p -i -e 's/^(10\d* )[A-Z ]{6}(.*)/$1XXXXXX$2/g' filename.txt
            

            【讨论】:

              猜你喜欢
              • 2016-04-22
              • 2015-02-04
              • 1970-01-01
              • 2021-07-04
              • 2018-04-05
              • 2014-03-20
              • 2014-07-29
              • 1970-01-01
              相关资源
              最近更新 更多