views:

184

answers:

5

Hi experts, In the past I have asked this question.But somehow I did not give the complete input.Input is a log file. I am trying to use sed to replace all but last four digits of credi card number.

sed -e :a -e "s/[0-9]\([0-9]\{4\}\)/\*\1/;ta" $today_temp_log

This expression definitely works but it replaces not just Credit card numbers but some otehr data too(where digits are more than 4). Input record which contains Credit Card number is of the format :

"CARD_NUMBER=[6362229292929290]"

So I need to replace record of above format.So the above record should be converted to

"CARD_NUMBER=[************9290]"

Thanks in advance.

+2  A: 

Assuming credit card number has 16 digits, I would try

sed -e :a -e "s/[0-9]\{12\}\([0-9]\{4\}\)/\*\*\*\*\*\*\*\*\*\*\*\*\1/;ta" $today_temp_log
Messa
Edited (and even tested). Thanks, KennyTM
Messa
thanks. Credit card number varies from 12 to 19(from wikipedia!).So this will work for only 16?
A: 
var1="CARD_NUMBER=[6362229292929290]"
IFS="="
set -- $var1
cardnumber=$2
result=$(echo $cardnumber | awk 'BEGIN{OFS=FS=""}{for(i=1;i<=NF-5 ;i++){ $i="*"} }1')
echo "$1=[$result"

output

$ ./shell.sh
CARD_NUMBER=[*************9290]

Or with awk

var1="CARD_NUMBER=[6362229292929290]"
echo $var1 | awk 'BEGIN{ OFS=FS="=" }
{
    gsub(/\[|\]/,"",$2)
    m=split($2,s,"")
    for(i=1;i<=m-4;i++){ s[i]="*" }
    str=$1 OFS "["
    for(i=1;i<=m;i++){ str=str s[i] }
    str=str "]"
}END{ print str } '

output

$ ./shell.sh
CARD_NUMBER=[************9290]

the above works for any digit length of card number

ghostdog74
A: 
sed -e :a -e "s/\(CARD_NUMBER=\[\**\)[0-9]\([0-9]\{4\}\)/\1\*\2/;ta"

Test case:

$ echo "blah=[123456789012345678] CARD_NUMBER=[6362229292929290] CARD_NUMBER=[13456]" | sed -e :a -e "s/\(CARD_NUMBER=\[\**\)[0-9]\([0-9]\{4\}\)/\1\*\2/;ta"
blah=[123456789012345678] CARD_NUMBER=[************9290] CARD_NUMBER=[*3456]
KennyTM
Thanks. this works.I understood the expression except- "[\**\)" part.
@user: `\[` matches a left square bracket, `\\**` matches zero or more stars, `\)` is the end of the capturing group.
KennyTM
A: 

Based on my answer here, this will mask the beginning of the number and leave the label, the brackets and the last four digits for card numbers of almost any number of digits:

sed -e 'h' -e 's/.*\([0-9]\{4\}\)/\1/' -e 'x' -e 's/\(.*\[\)\([0-9]*\)\([0-9]\{4\}\)./\1\2/' -e 's/[0-9]/*/g' -e 'G' -e 's/\n//'

If you need to validate that the total number of digits only falls within a given range, that can be done, too.

Edit:

Here's a couple of ways:

Pass through numbers unchanged that are too long or too short:

sed -e '/.*\[[0-9]\{12,19\}\]/!b' -e 'h' -e 's/.*\([0-9]\{4\}\)/\1/' -e 'x' -e 's/\(.*\[\)\([0-9]*\)\([0-9]\{4\}\)./\1\2/' -e 's/[0-9]/*/g' -e 'G' -e 's/\n//'
CARD_NUMBER=[12345678] yields CARD_NUMBER=[12345678]  
CARD_NUMBER=[123456789012] yields CARD_NUMBER=[********9012]
CARD_NUMBER=[12345678901234567890] yields CARD_NUMBER=[12345678901234567890]

Mask all digits of numbers that are too long or too short using a different mask character:

sed -e '/.*\[[0-9]\{12,19\}\]/!{s/[0-9]/x/g;b}' -e 'h' -e 's/.*\([0-9]\{4\}\)/\1/' -e 'x' -e 's/\(.*\[\)\([0-9]*\)\([0-9]\{4\}\)./\1\2/' -e 's/[0-9]/*/g' -e 'G' -e 's/\n//'
CARD_NUMBER=[12345678] yields CARD_NUMBER=[xxxxxxxx]  
CARD_NUMBER=[123456789012] yields CARD_NUMBER=[********9012]  
CARD_NUMBER=[12345678901234567890] yields CARD_NUMBER=[xxxxxxxxxxxxxxxxxxxx]
Dennis Williamson
Thanks.Digits are from 12 to 19.
A: 

You can use the address fields within sed to limit the replacement to lines that match a particular pattern. So simply add /CARD_NUMBER=/ to the start of your expression, giving

sed -e :a -e "/CARD_NUMBER=/s/[0-9]\([0-9]\{4\}\)/\*\1/;ta" $today_temp_log
Beano