1

Suppose I have two files like below and i would like to substract the values from two files:-

File 1 -

emcas_bdl_migrate=2
emcas_biaas_dev=691
emcas_brs_ba=462
emcas_cc_analytics=1985
emcas_clm_reporting=0
emcas_collab_xsat=3659
emcas_cpsd_cee=10
emcas_cpsd_hcp=0
emcas_e2ep_ba=81
emcas_edservices_bi=643

And File 2 -

emcas_bdl_migrate=2
emcas_biaas_dev=63
emcas_brs_ba=430
emcas_cc_analytics=2148
emcas_clm_reporting=16
emcas_collab_xsat=4082
emcas_cpsd_cee=11
emcas_cpsd_hcp=0
emcas_cs_logistics=0
emcas_e2ep_ba=195
emcas_edservices_bi=1059

There can be extra values for File 2 (eg. emcas_cs_logistics=0 in 2nd file extra). Which will be merged in the final output file.

Want a desired output as File 3 -

emcas_bdl_migrate=0
emcas_biaas_dev=-628
emcas_brs_ba=-32
emcas_cc_analytics=163
emcas_clm_reporting=16
emcas_collab_xsat=423
emcas_cpsd_cee=11
emcas_cpsd_hcp=0
emcas_cs_logistics=0
emcas_e2ep_ba=-114
emcas_edservices_bi=416
0

Here's an approach using Python. Note that this is a classic case for the Counter collection

#!/usr/bin/env python3

import argparse
from collections import Counter

def read(f):
    """Reads the contents of param=value file and returns a dict"""
    d = {}

    with open(f,'r') as fin:
        for item in fin.readlines():
            s = item.split('=')
            d[s[0]] = int(s[1])

    return d

def write(f, d):
    """Writes dict d to param=value file 'f'"""

    with open(f, 'w') as fout:
        for k,v in sorted(d.items()):
            fout.write('{}={}\n'.format(k,v))

def subtract(d1, d2):
    """
    Subtracts values in d2 from d1 for all params and returns the result in result.
    If an item is present in one of the inputs and not the other, it is added to
    result.

    Note: order of arguments plays a role in the sign of the result.
    """
    c = Counter(d1.copy())
    c.subtract(d2)
    return c

if __name__ == "__main__":

    parser = argparse.ArgumentParser()
    parser.add_argument('file1', type=str, help='path to file 1')
    parser.add_argument('file2', type=str, help='path to file 2')
    parser.add_argument('outfile', type=str, help='path to output file')

    args = parser.parse_args()

    d1 = read(args.file1)
    d2 = read(args.file2)

    d3 = subtract(d1,d2)

    write(args.outfile, d3)

Save the code above to a file named subtract_params and add executable permissions. It can then be called like:

subtract_params file1.txt file2.txt result.txt 
1

You can use awk for this:

awk -F= 'NR==FNR{a[$1]=$2;next}{printf "%s=%s\n",$1,$2-a[$1]}' file1 file2
  • This is so compact and cool! – ephsmith Oct 3 '18 at 15:55
1

Try also

awk -F= -vOFS="=" 'NR==FNR {T[$1] = $2; next} {$2 -= T[$1]} 1' file[12]
emcas_bdl_migrate=0
emcas_biaas_dev=-628
emcas_brs_ba=-32
emcas_cc_analytics=163
emcas_clm_reporting=16
emcas_collab_xsat=423
emcas_cpsd_cee=1
emcas_cpsd_hcp=0
emcas_cs_logistics=0
emcas_e2ep_ba=114
emcas_edservices_bi=416

This collects file1's values $2 in the T array indexed by the token in $1. Then, reading file2, it subtracts the respective T element from file2's value (or 0 if non-existent) before printing. The result deviates in two positions from your desired output; you may want to double check for typos.

1

One way to do this is to use associative arrays. This this:

#!/bin/bash

# Declare a to be an associative array
declare -A a

# Read in file2, populating the associative array
while read l; do
  k=${l%=*}
  v=${l#*=}
  a[${k}]=${v}
done <file2.txt

# Read in file1.  Subtract the value for a key in file1
# from what was populated into the array from file2.
while read l; do
  k=${l%=*}
  v=${l#*=}
  (( a[${k}] -= ${v} ))
done <file1.txt

# Print out the resulting associative array.
for k in ${!a[@]}; do
  echo "${k}: ${a[${k}]}"
done

exit 0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.