match column and delete the Duplicates in Shell

Viewed 73

Input file

Failed,2021-12-14 05:47 EST,On-Demand Backup,abc,/clients/FORD_1130PM_EST_Windows2008,Windows File System
Completed,2021-12-14 05:47 EST,On-Demand Backup,def,/clients/FORD_1130PM_EST_Windows2008,Windows File System
Failed,2021-12-13 19:33 EST,Scheduled Backup,def,/clients/FORD_730PM_EST_Windows2008,Windows File System  
Failed,2021-12-14 00:09 EST,Scheduled Backup,abc,/clients/FORD_1130PM_EST_Windows2008,Windows File System
Failed,2021-12-14 00:09 EST,Scheduled Backup,ghi,/clients/FORD_1130PM_EST_Windows2008,Windows File System

Expected Output

Failed,2021-12-14 00:09 EST,Scheduled Backup,ghi,/clients/FORD_1130PM_EST_Windows2008,Windows File System

I want only those clients which are never successful and there is no on-demand backup run for them.

Code I tried

awk -F ',' '
   $1~/Failed/  { fail[$4]=$0 }
  $1~/Completed/ {delete fail[$4]}
 $3 ~ /Demand/ {delete fail[$4]}
END {for (i in fail) print fail[i]}     
 ' test
3 Answers

You can use this awk command:

awk -F, 'NR==FNR {if ($1~/Failed/) fail[$4] = $0; next}
$1 ~ /Completed/ || $3 ~ /Demand/ {delete fail[$4]}
END {for (i in fail) print fail[i]}' file file

Failed,2021-12-14 00:09 EST,Scheduled Backup,ghi,/clients/FORD_1130PM_EST_Windows2008,Windows File System

With your shown samples, please try following awk program. In a single pass of Input_file. This will print only those values which are failed and never have any on-demand in their values as per shown samples.

awk '
BEGIN         { FS=OFS=","  }
$1=="Failed"  { arr1[$4]=$0 }
$3~/On-Demand/{ arr2[$4]    }
END{
  for(key in arr1){
    if(!(key in arr2)){
      print arr1[key]
    }
  }
}
' Input_file

Explanation: Adding detailed explanation for above.

awk '                           ##Starting awk program from here.
BEGIN         { FS=OFS=","  }   ##Starting BEGIN section and setting FS and OFS to , here.
$1=="Failed"  { arr1[$4]=$0 }   ##Checking if 1st field is Failed then create arr1 with 4th field as an index and value of whole line.
$3~/On-Demand/{ arr2[$4]    }   ##Checking if 3rd field is On-Demand then create arr2 array with index of 4th field.
END{                            ##Starting END block of this program from here.
  for(key in arr1){             ##Traversing through arr1 here.
    if(!(key in arr2)){         ##Checking condition if key is NOT present in arr2 then do following.
      print arr1[key]           ##Printing arr1 value with index of key here.
    }
  }
}
' Input_file                    ##Mentioning Input_file here.

Here is a ruby that will handle multiple entries (if any) and csv quirks such as embedded commas:

ruby -r csv -e '
BEGIN{hsh = Hash.new {|hash,key| hash[key] = []}
      data = Hash.new {|hash,key| hash[key] = []}
}
CSV.parse($<.read).each{ |r|    hsh[r[3]] << r[0]; hsh[r[3]] << r[2]
                                data[r[3]] << r.to_csv
                        }
END{hsh.each{|k,v| s=v.join("\t")
    puts data[k].join() if !s[/Completed|Demand/] }
}' file

Prints:

Failed,2021-12-14 00:09 EST,Scheduled Backup,ghi,/clients/FORD_1130PM_EST_Windows2008,Windows File System
Related