【问题标题】:Mask output card number with ****用****屏蔽输出卡号
【发布时间】:2021-11-25 07:44:43
【问题描述】:

我的任务是在给定输入文件的情况下用星号 (*) 屏蔽每个信用卡号的前 12 位数字,并将屏蔽后的数字打印到输出文件中。

卡号示例:

1111-2222-3333-4444
4444-3333-2222-1111
1234-5678-9101-1171
1234 5678 9101 1121
7347_9834_7598_2834
8973#9858#3475#8734
2356`7843`0527`5340
8734=7583=4895=7007
8763+2430+6257_9406

一切都应该在 shell 脚本中完成

我的解决办法是:

#!/bin/bash

file='cards.txt'
while read data; do
echo $data | sed -r 's/[[:digit:]]{4}/****/;s/[[:digit:]]{4}/****/;s/[[:digit:]]{4}/****/;s/[^0-9,*]+/ /g'
done < $file > cards-masked.txt

关于如何在此任务中使用 sed 有什么更好的想法吗?

【问题讨论】:

    标签: bash shell sed script


    【解决方案1】:

    查看示例数据,您似乎总是有 4 个数字,由一个数字以外的字符分隔。

    如果您也有兴趣使用 awk 解决方案,您可以先用空格替换除数字之外的所有字符。

    然后将前 3 列中的所有字符替换为 *

    awk '{gsub(/[^0-9]+/, " ");for (i=1;i<4;i++) gsub(/[0-9]/,"*",$i)}1' cards.txt > cards-masked.txt
    

    一个更易读的版本,带有简短的解释

    awk '{
      gsub(/[^0-9]+/, " ")                    # Replace all chars other than 0-9 with a space
      for (i=1;i<4;i++) gsub(/[0-9]/,"*",$i)  # Loop the first 3 columns, replace all digits with *
    }1' cards.txt > cards-masked.txt          # The 1 evaluates to true, printing the whole line
    

    输出

    **** **** **** 4444
    **** **** **** 1111
    **** **** **** 1171
    **** **** **** 1121
    **** **** **** 2834
    **** **** **** 8734
    **** **** **** 5340
    **** **** **** 7007
    **** **** **** 9406
    

    【讨论】:

      【解决方案2】:

      第一个解决方案: 使用简单的sed 执行 3 次 4 位数字替换为 4 * 每次都设置好了。

      sed -E 's/[[:digit:]]{4}/****/;s/[[:digit:]]{4}/****/;s/[[:digit:]]{4}/****/' Input_file
      


      第二个解决方案: 使用awk 程序,只需使用3 次sub(substitute) 函数即可完成。

      awk '{sub(/[[:digit:]]{4}/,"****");sub(/[[:digit:]]{4}/,"****");sub(/[[:digit:]]{4}/,"****")} 1' Input_file
      

      【讨论】:

      • 我做的和你写的一模一样!但最后添加了;s/[^0-9,*]+/ /g 以删除任何符号,所以它看起来像**** **** **** nnnn
      【解决方案3】:

      如果您的输入总是在每个第 4 位数字之后有一个非数字分隔符,那么使用gnu-awk,您可以使用RS 和RT 轻松完成。

      使用-v RS='[^0-9]',我们将每条记录拆分为非数字字符,并使用模块将每条记录设置为****,当记录号不能被4整除时。最后使用ORS=RT,我们将捕获的非数字字符放在输出中,以获得与输入相同的分隔符。

      awk -v RS='[^0-9]' 'NR%4 {$0="****"} {ORS=RT} 1' file > output
      
      cat output
      
      ****-****-****-4444
      ****-****-****-1111
      ****-****-****-1171
      **** **** **** 1121
      ****_****_****_2834
      ****#****#****#8734
      ****`****`****`5340
      ****=****=****=7007
      ****+****+****_9406
      

      【讨论】:

        【解决方案4】:

        很简单:

        cat cards.txt|rev|sed -e 's/[[:digit:]]/*/5g' |rev > cards-masked.txt
        
        echo "1234-5678-9123-1234"|rev|sed -e 's/[[:digit:]]/*/5g' |rev
        ****-****-****-1234
        

        这是反向任务:

        cat cards.txt|sed -e 's/[[:digit:]]/*/13g' > cards-masked.txt
        

        如您所见,while/read 循环也不需要。每一个 sed 表达式都会被逐行计算。

        【讨论】:

        • 谢谢。但是,如果我需要输出为:**** **** **** 1234 我们该怎么做呢?
        • @arheops : 如果你去掉 cat 会更简单。
        • @isvalx : 1234 来自哪里?我无法从您的问题中理解这一点。
        • @isvalx 它会按照您的要求输出,只需测试它。
        【解决方案5】:

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

        sed -E '/([0-9]{4}[ #`=+-_]){3}[0-9]{4}/{s//\n&\n/;h
               s/[0-9]/*/g;G;s/.*\n(.*)\n.*\n(.*)\n.*\n/\2\1/}' file
        

        用换行符包围匹配项。

        复制一份。

        将所有数字替换为*'s

        附加副本。

        使用模式匹配,将原始匹配替换为修改后的匹配。

        可以扩展为一行中的多个匹配项:

        sed -E ':a;/([0-9]{4}[ #`=+-_]){3}[0-9]{4}/{s//\n&\n/;h
               s/[0-9]/*/g;G;s/.*\n(.*)\n.*\n(.*)\n.*\n/\2\1/;ta}' file
        

        要仅替换前九位,请使用:

        sed -E ':a;/(([0-9]{4}[ #`=+-_]){3})([0-9]{4})/{s//\n\1\n\3/;h
               s/[0-9]/*/g;G;s/.*\n(.*)\n.*\n(.*)\n.*\n/\2\1/;ta}' file
        

        【讨论】:

        • 大声笑。这真的很简单。需要花……小时?了解这种简单性。
        • @arheops 或许可以看到here
        • 但是如果与原始变体或我的变体相比,它有多简单?我知道有很多复杂的方法可以做到这一点。但是为什么?
        • @arheops 这是一个通用解决方案,有望涵盖大多数边缘情况。当候选人来寻找类似的解决方案时,这可能是这些人的起点。
        【解决方案6】:

        替换前 15 个字符:

        sed -e 's/^.\{15\}/**** **** **** /' < file
        

        输出:

        **** **** **** 4444
        …
        **** **** **** 9406
        

        相同,但将字符保留在位置 5、10 和 15:

        sed -e 's/^....\(.\)....\(.\)....\(.\)/****\1****\2****\3/' < file
        

        输出:

        ****-****-****-4444
        …
        ****+****+****_9406
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-02-22
          • 1970-01-01
          • 1970-01-01
          • 2018-04-28
          • 2013-12-25
          • 2011-11-20
          • 2023-03-13
          相关资源
          最近更新 更多