用****屏蔽输出卡号
Posted
技术标签:
【中文标题】用****屏蔽输出卡号【英文标题】: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 有什么更好的想法吗?
【问题讨论】:
【参考方案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
【讨论】:
以上是关于用****屏蔽输出卡号的主要内容,如果未能解决你的问题,请参考以下文章