need to remove duplicates based on key in first column and pattern in last column

Given a file such as this I need to remove the duplicates.

00060011    PAUL BOWSTEIN          ad_waq3_921_20100826_010517.txt
00060011    PAUL BOWSTEIN          ad_waq3_921_20100827_010528.txt

0624-01    RUT CORPORATION    ad_sade3_10_20100827_010528.txt
0624-01    RUT CORPORATION    ad_sade3_10_20100826_010517.txt

00000010    JONES, PAUL        ad_sade3_933_20100826_010517.txt
00000010    JONES, PAUL        ad_sade3_933_20100827_010528.txt
  • The key is the first column.
  • The last column determines which record to keep, that is delete all other duplicates and only keep that one. The last column with the greatest date and time should be kept as shown in bold.
awk '{split($4,a,"_"); if (b[$1]<=a[4]a[5]) {b[$1]=a[4]a[5];c[$1]=$0}}
END{for (i in b) print c}' infile
1 Like

Hello again,

I ran the script and it does indeed work.

The only thing I don't understand is how it is able to evaluate the fist line of the key as true in order to assign the value to the array.

I added some print statements to show that it does evaluate to true.

#!/bin/sh
awk '{split($4,a,"_"); if (b[$1]<=a[4]a[5]) {print "true", $1, b[$1];b[$1]=a[4]a[5];c[$1]=$0}}
END{for (i in b) print c}' dups.txt

this is the output of the modified script with the print statements showing that it evaluates to true for each first occurrence of the key value (field #1)

true 00060011 
true 00060011 20100826010517.txt
true 0624-01 
true 00000010 
true 00000010 20100826010517.txt
00000010 JONES, PAUL ad_sade3_933_20100827_010528.txt
00060011 PAUL BOWSTEIN ad_waq3_921_20100827_010528.txt
0624-01 RUT CORPORATION ad_sade3_10_20100827_010528.txt

Could you or someone explain to me how b[$1]<=a[4]a[5] evaluates to true for the first line?

Is it saying the same as b[00060011]<=20100826010517.txt ?

When it does this in the 1st record, at this point b[$1] has No Value right?
And from what I understand about if statements in awk, they cannot be 0.

Is the value null or an empty string??

Yes, for the fist record with key 'k' the value of b[k] will be 0 or the empty string depending on whether the value is used in an equation or as a string. In this case, the expression is the comparison of the empty string with some non-empty string; a non-empty string will always test greater than "". Thus, for the first instance of the key the value will be saved.

I'm not quite sure what you mean by an if statement cannot be zero.

What I mean is that in order to execute what follows the relational operation of the if statement the value cannot be 0.

For example:

#!/bin/sh
awk '{split($4,a,"_"); if (b[$1]) {print "this is b[$1]" b[$1]}}' dups.txt

This returns absolutely nothing because b[$1] is 0. Or is it?
Or is it an empty string? How can you tell?

But if you do it like this:
from the working script

if (b[$1]<=a[4]a[5])

It does NOT evaluate to 0 and continues to what follows the if.

I guess my real question is what value does b[$1] have by itself.

What value does an empty array have in awk when no values has been assigned yet?

If it's 0, I don't understand because how can you say 0>=20100826010517.txt ?

If it IS an empty string when no values have been assigned to it yet then it would be "">=20100826010517.txt . Which I Can understand.

Could you or anyone point me to some online documentation that specifically states if the value is of an empty array 0 or "an empty string" or what it is?
Or a quote from a specific book?

if no value assign to b[$1] , b[$1] will be "" (empty) initially, but when compare in awk, it will be considered as 0.

the first a[4]a[5] is 20100826010517.txt, (has .txt in it), when compare in awk, awk is smart enough to take out all non-digital characters, and consider it as 20100826010517, then if condition is translated to :

 if (0 <= 20100826010517)

That's very good to know.

Is there a reason to have a[4]a[5] , why not just use a[4] and then awk doesn't even have to remove anything?

Using both allows the timestamp to be used in determining the most recent entry which would be necessary should two entries have the same date.

Hello,

Could anyone help me modify this script to output 1 file containing the unwanted duplicates and the other containing just the desired records?

a simple solution, base on previous script.

awk '{split($4,a,"_"); if (b[$1]<=a[4]a[5]) {b[$1]=a[4]a[5];c[$1]=$0}}
END{for (i in b) print c}' infile  |sort > desired_records

sort infile > temp2

diff desired_records temp2 |awk '/^>/ {$1="";print}'> unwanted_duplicates_records 
1 Like
sort -t_ -k1,1 -k4rn < infile | awk -F_ 'NF{if(A[$1,$2,$3]++)print>"dups.out";else print}' > recs.out

This almost works. The only problem is that it puts a blank space in front of every line in the

unwanted_duplicates_records

file.

Is there any way we can fix this?

diff desired_records temp2 |awk '/^>/ {$1="";print}'|sed 's/^ //' > unwanted_duplicates_records

This is what I finally used:

diff $outfile $temp_sort_file |awk '/^>/ {print $0}'|sed 's/^> //' > $temp_dups_file

It works with most of my files.

I'm trying to understand it.

What is the awk part doing exactly? What is

^>

?

And what is the sed part doing? What is

's/^> //'

?