How to find a match to a partial string and then delete the string from the reference file using awk?

Viewed 76

I have a problem that I have been trying to solve, but have not been able to figure out how to do it. I have a reference file that has all of the devices in my inventory by bar code.

Reference file:

PTR10001,PRINTER,SN A
PTR10002,PRINTER,SN B
PTR10003,PRINTER,SN C 
MON10001,MONITOR,SN A
MON10002,MONITOR,SN B
MON10003,MONITOR,SN C
CPU10001,COMPUTER,SN A
CPU10002,COMPUTER,SN B
CPU10003,COMPUTER,SN C

What I would like to do is make a file where I only have to put the abbreviation of what I need on it. File 2 would look like this:

PTR
CPU
MON
MON

The desired output of this would be a file that would tell me what items by barcode that I need to pull off the shelf.
Desired output file:

PTR10001
CPU10001
MON10001
MON10002

As seen in the output, since I cannot have 2 of the same barcode, I need it to look through the reference file and find the first match. After the number is copied to the output file, I would like to remove the number from the reference file so that it doesn't repeat the number.

I have tried several iterations of awk, but have not been able get the desired output.
The closest that I have gotten is the following code:

awk -F'/' '{ key = substr($1,1,3) } NR==FNR {id[key]=$1; next} key in id { $1=id[key] } { print }' $file1 $file2 > $file3

I am writing this in ksh, and would like use awk as I think this would be the best answer to the problem. Thanks for helping me with this.

2 Answers

First solution:

From your detailed description, I assume order doesn't matter, as you want to know what to pull off the shelf. So you could do the opposite, first read file2, count the items, and then go to the shelf and get them.

awk -F, 'FNR==NR{c[$0]++; next} c[substr($1,1,3)]-->0{print $1}' file2 file1

output:

PTR10001
MON10001
MON10002
CPU10001

Second solution:

Your awk is very close to what you want, but you need a second dimension in your array, and not overwriting the existing ids. We will do it with a pseudo-2-d array (BTW GNU awk has real 2-dimensional arrays) where we store the ids like PTR10001,PTR10002,PTR10003, we retrieve them with split and we remove from shelf also.

> cat tst.awk
BEGIN { FS="," }

NR==FNR {
    key=substr($1,1,3)
    ids[key] = (ids[key]? ids[key] "," $1: $1) #append new id.
    next
}

$0 in ids {
    split(ids[$0], tmp, ",")
    print(tmp[1])
    ids[$0]=substr(ids[$0],length(tmp[1])+2) #remove from shelf
}

Output

awk -f tst.awk file1 file2
PTR10001
CPU10001
MON10001
MON10002

Here we keep the order of file2 as this is based on the idea you have tried.

Could you please try following, written and tested with shown samples in GNU awk.

awk '
FNR==NR{
  iniVal[$0]++
  next
}
{
  counter=substr($0,1,3)
}
counter in iniVal{
  if(++currVal[counter]<=iniVal[counter]){
     print $1
     if(currVal[counter]==iniVal[counter]){ delete iniVal[$0] }
  }
}
' Input_file2  FS="," Input_file1

Explanation: Adding detailed explanation for above.

awk '                                           ##Starting awk program from here.
FNR==NR{                                        ##Checking condition if FNR==NR which is true when Input_file2 is being read.
  iniVal[$0]++                                  ##Creating array iniVal with index of current line with increment of 1 each time it comes here.
  next                                          ##next will skip all further statements from here.
}
{
  counter=substr($0,1,3)                        ##Creating counter variable which has 1st 3 characters of Input_file1 here.
}
counter in iniVal{                              ##Checking if counter is present in iniVal then do following.
  if(++currVal[counter]<=iniVal[counter]){      ##Checking if currValarray with index of counter value is lesser than or equal to iniVal then do following.
     print $1                                   ##Printing 1st field of current line here.
     if(currVal[counter]==iniVal[counter]){     ##Checking if currVal value is equal to iniVal with index of counter here.
       delete iniVal[$0]                        ##If above condition is TRUE then deleting iniVal here.
     }
  }
}
' Input_file2  FS="," Input_file1               ##Mentioning Input_file names here.
Related