Home > Software design >  Comparing two files with respective fields and output required in a specific format
Comparing two files with respective fields and output required in a specific format

Time:02-12

I am comparing two files

food1.txt file and compares food2.txt file, like this

# cat food1.txt 
pizza=1ea
chicken=5ea
tooboo=4ea
orange=2ea
# cat food2.txt 
pizza=2ea
chicken=5ea
grape=3ea
tooboo=4ea
melon=1ea
  • my work...
FOOD1=`cat ./food1.txt`
FOOD2=`cat ./food2.txt`

echo "$FOOD1" | while read ACCOUNT
do
grep -w $ACCOUNT ./food2.txt  >/dev/null 2>&1
if [ $? -eq 0 ] ; then
echo "-----[  OK  ] : $ACCOUNT"
else
echo "-----[ WARN ] : $ACCOUNT"
fi
done 
  • output.. but i don't like it
-----[ WARN ] : pizza=1ea
-----[  OK  ] : chicken=5ea
-----[  OK  ] : tooboo=4ea
-----[ WARN ] : orange=2ea

I want to print the comparison target together

  • I want output, like this
food2.txt                   food1.txt
pizza=2ea   : [ NotMatch ] : pizza=1ea
            : [    OK    ] : chicken=5ea
            : [    OK    ] : tooboo=4ea
            : [ NotExist ] : orange=2ea
grape=3ea   : [ NotExist ] :
melon=1ea   : [ NotExist ] :

Is it possible? please help me.

CodePudding user response:

With your shown samples, please try following awk program. Written and tested in GNU awk.

awk '
BEGIN{
  FS="="
  print ARGV[1]"                   "ARGV[2]
}
FNR==NR{
  arr1[$1]=$2
  next
}
($1 in arr1){
  if($2==arr1[$1]){
     print  "           :[    OK     ] : " $0
  }
  else if($2!=arr1[$1]){
     print $1 FS arr1[$1]"  :[ NotMatch  ] : "$0
  }
  arr2[$1]
  next
}
{
  print $0"  :[ NotExist  ] : "
}
END{
  for(i in arr1){
     if(!(i in arr2)){
        print "           :[ NotExist  ] : "i FS arr1[i]
     }
  }
}
' food1.txt food2.txt

With your shown samples, following will be output:

food1.txt                   food2.txt
pizza=1ea  :[ NotMatch  ] : pizza=2ea
           :[    OK     ] : chicken=5ea
grape=3ea  :[ NotExist  ] :
           :[    OK     ] : tooboo=4ea
melon=1ea  :[ NotExist  ] :
           :[ NotExist  ] : orange=2ea

Explanation: Adding detailed explanation for above code.

awk '                                                        ##Starting awk program from here.
BEGIN{                                                       ##Starting BEGIN section from here.
  FS="="                                                     ##Setting field separator as = here.
  print ARGV[1]"                   "ARGV[2]                  ##Printing passed Input_file names here.
}
FNR==NR{                                                     ##Checking condition FNR==NR which will be TRUE when food1.txt is being read.
  arr1[$1]=$2                                                ##Creating array named arr1 with index of 1st field and value is $2.
  next                                                       ##next will skip all further statements from here.
}
($1 in arr1){                                                ##Checking condition if $1 is present in arr1 then do following.
  if($2==arr1[$1]){                                          ##Checking condition if 2nd field is equal to arr1 value.
     print  "           :[    OK     ] : " $0                ##Printing ok message with current line of food2.txt here.
  }
  else if($2!=arr1[$1]){                                     ##Else(in case 2nd field is NOT equal to arr1 value) then do following.
     print $1 FS arr1[$1]"  :[ NotMatch  ] : "$0             ##Printing first field FS value of arr1 followed by NotMatch followed by current line from food2.txt.
  }
  arr2[$1]                                                   ##Making an entry of current $1 for arr2 array here.
  next                                                       ##next will skip all further statements from here.
}
{
  print $0"  :[ NotExist  ] : "                              ##printing current line followed by NotExist statement.
}
END{                                                         ##Starting END block for this program from here.
  for(i in arr1){                                            ##Traversing through arr1 elements here.
     if(!(i in arr2)){                                       ##Checking condition if key i is NOT present in arr2 then do following.
        print "           :[ NotExist  ] : "i FS arr1[i]     ##printing NOtExist statements followed by i FS and arr1 value.
     }
  }
}
' food1.txt food2.txt                                        ##Mentioning Input_file names here.

CodePudding user response:

As bash is tagged, here's a solution using associative arrays. The first while loop populates the array reading the first file. The second while loop iterates over the second file, checks whether keys and/or values match with entries in the array, and deletes them. Finally the for loop iterates over the remaining "unchecked" items in the array.

out() {
  if   [[      -z "$3" ]]; then l="$1"    m="                " r="$2"
  elif [[      -z "$2" ]]; then l="$3=$1" m=": [ NotExist ] :" r=""
  elif [[      -z "$1" ]]; then l=""      m=": [ NotExist ] :" r="$3=$2"
  elif [[ "$2" == "$1" ]]; then l=""      m=": [    OK    ] :" r="$3=$2"
  else                          l="$3=$1" m=": [ NotMatch ] :" r="$3=$2"; fi
  printf '%-10s %s %-10s\n' "$l" "$m" "$r"
}

f1=food1.txt
f2=food2.txt

out "$f2" "$f1"

declare -A f
while IFS== read -r k v; do f[$k]=$v; done < "$f2"

while IFS== read -r k v; do out "${f[$k]}" "$v" "$k"; unset f[$k]; done < "$f1"

for k in "${!f[@]}"; do out "${f[$k]}" "" "$k"; done
food2.txt                   food1.txt 
pizza=2ea  : [ NotMatch ] : pizza=1ea 
           : [    OK    ] : chicken=5ea
           : [    OK    ] : tooboo=4ea
           : [ NotExist ] : orange=2ea
grape=3ea  : [ NotExist ] :           
melon=1ea  : [ NotExist ] :
  • Related