#!/bin/bash
# ideone boilerplate - we can't write files in the home directory;
# so create a temporary directory for our files instead
t=$(mktemp -d -t ideone.XXXXXXXXXXXX) || exit
trap 'rm -rf "$t"' ERR EXIT
cd "$t"
cat <<\: >zulu_db_capcodes.txt
capcode,discipline,region,location,description,remark
000400001,Brandweer,Groningen,Groningen,Regionaal,Pelotonscommandant Logistiek/Water (Noord)
000400002,Brandweer,Groningen,Groningen,,
000400003,Brandweer,Groningen,Groningen,Regionaal,Pelotonscommandant Logistiek/Water) (Oost)
000100000,Brandweer,Amsterdam-Amstelland,Amsterdam-Amstelland,Aalsmeer,Postalarm
000100001,Brandweer,Amsterdam-Amstelland,Amsterdam-Amstelland,,
000100002,Brandweer,Amsterdam-Amstelland,Amsterdam-Amstelland,,Banaanzulu
000100003,Brandweer,Amsterdam-Amstelland,Amsterdam-Amstelland,,
:
cat <<\: >bommel_db_capcodes.txt
capcode,discipline,region,location,description,remark
000100000,Brandweer,Amsterdam-Amstelland,,banaanProefalarm,
000100001,Brandweer,Amsterdam-Amstelland,Aalsmeer,Bevelvoerders,
000100004,Brandweer,Amsterdam-Amstelland,Aalsmeer,Korpsalarm,
:
cat <<\: >demo.py
#!/usr/bin/env python3
import csv
fields = ['capcode', 'discipline', 'region', 'location', 'description', 'remark']
with open('bommel_db_capcodes.txt', 'r') as readFile_bommel, \
open('results.csv', 'w') as results, \
open('zulu_db_capcodes.txt', 'r') as readFile_zulu:
master = csv.DictReader(readFile_zulu, fieldnames=fields)
update = csv.DictReader(readFile_bommel, fieldnames=fields)
writer = csv.DictWriter(results, fieldnames=fields)
# Saves and skips header to output file
writer.writerow(next(master))
# Skip header from updates
next(update)
# Read, remember, and write updated lines
seen = set()
for row in update:
writer.writerow(row)
seen.add(row['capcode'])
for row in master:
if row['capcode'] not in seen:
writer.writerow(row)
:
python3 demo.py
nl results.csv
IyEvYmluL2Jhc2gKCiMgaWRlb25lIGJvaWxlcnBsYXRlIC0gd2UgY2FuJ3Qgd3JpdGUgZmlsZXMgaW4gdGhlIGhvbWUgZGlyZWN0b3J5OwojIHNvIGNyZWF0ZSBhIHRlbXBvcmFyeSBkaXJlY3RvcnkgZm9yIG91ciBmaWxlcyBpbnN0ZWFkCnQ9JChta3RlbXAgLWQgLXQgaWRlb25lLlhYWFhYWFhYWFhYWCkgfHwgZXhpdAp0cmFwICdybSAtcmYgIiR0IicgRVJSIEVYSVQKY2QgIiR0IgoKY2F0IDw8XDogPnp1bHVfZGJfY2FwY29kZXMudHh0CmNhcGNvZGUsZGlzY2lwbGluZSxyZWdpb24sbG9jYXRpb24sZGVzY3JpcHRpb24scmVtYXJrCjAwMDQwMDAwMSxCcmFuZHdlZXIsR3JvbmluZ2VuLEdyb25pbmdlbixSZWdpb25hYWwsUGVsb3RvbnNjb21tYW5kYW50IExvZ2lzdGllay9XYXRlciAoTm9vcmQpCjAwMDQwMDAwMixCcmFuZHdlZXIsR3JvbmluZ2VuLEdyb25pbmdlbiwsCjAwMDQwMDAwMyxCcmFuZHdlZXIsR3JvbmluZ2VuLEdyb25pbmdlbixSZWdpb25hYWwsUGVsb3RvbnNjb21tYW5kYW50IExvZ2lzdGllay9XYXRlcikgKE9vc3QpCjAwMDEwMDAwMCxCcmFuZHdlZXIsQW1zdGVyZGFtLUFtc3RlbGxhbmQsQW1zdGVyZGFtLUFtc3RlbGxhbmQsQWFsc21lZXIsUG9zdGFsYXJtCjAwMDEwMDAwMSxCcmFuZHdlZXIsQW1zdGVyZGFtLUFtc3RlbGxhbmQsQW1zdGVyZGFtLUFtc3RlbGxhbmQsLAowMDAxMDAwMDIsQnJhbmR3ZWVyLEFtc3RlcmRhbS1BbXN0ZWxsYW5kLEFtc3RlcmRhbS1BbXN0ZWxsYW5kLCxCYW5hYW56dWx1CjAwMDEwMDAwMyxCcmFuZHdlZXIsQW1zdGVyZGFtLUFtc3RlbGxhbmQsQW1zdGVyZGFtLUFtc3RlbGxhbmQsLAo6CgpjYXQgPDxcOiA+Ym9tbWVsX2RiX2NhcGNvZGVzLnR4dApjYXBjb2RlLGRpc2NpcGxpbmUscmVnaW9uLGxvY2F0aW9uLGRlc2NyaXB0aW9uLHJlbWFyawowMDAxMDAwMDAsQnJhbmR3ZWVyLEFtc3RlcmRhbS1BbXN0ZWxsYW5kLCxiYW5hYW5Qcm9lZmFsYXJtLAowMDAxMDAwMDEsQnJhbmR3ZWVyLEFtc3RlcmRhbS1BbXN0ZWxsYW5kLEFhbHNtZWVyLEJldmVsdm9lcmRlcnMsCjAwMDEwMDAwNCxCcmFuZHdlZXIsQW1zdGVyZGFtLUFtc3RlbGxhbmQsQWFsc21lZXIsS29ycHNhbGFybSwKOgoKY2F0IDw8XDogPmRlbW8ucHkKIyEvdXNyL2Jpbi9lbnYgcHl0aG9uMwppbXBvcnQgY3N2CgoKZmllbGRzID0gWydjYXBjb2RlJywgJ2Rpc2NpcGxpbmUnLCAncmVnaW9uJywgJ2xvY2F0aW9uJywgJ2Rlc2NyaXB0aW9uJywgJ3JlbWFyayddCgp3aXRoIG9wZW4oJ2JvbW1lbF9kYl9jYXBjb2Rlcy50eHQnLCAncicpIGFzIHJlYWRGaWxlX2JvbW1lbCwgXAogICAgICAgIG9wZW4oJ3Jlc3VsdHMuY3N2JywgJ3cnKSBhcyByZXN1bHRzLCBcCiAgICAgICAgb3BlbignenVsdV9kYl9jYXBjb2Rlcy50eHQnLCAncicpIGFzIHJlYWRGaWxlX3p1bHU6CgogICAgbWFzdGVyID0gY3N2LkRpY3RSZWFkZXIocmVhZEZpbGVfenVsdSwgZmllbGRuYW1lcz1maWVsZHMpCiAgICB1cGRhdGUgPSBjc3YuRGljdFJlYWRlcihyZWFkRmlsZV9ib21tZWwsIGZpZWxkbmFtZXM9ZmllbGRzKQogICAgd3JpdGVyID0gY3N2LkRpY3RXcml0ZXIocmVzdWx0cywgZmllbGRuYW1lcz1maWVsZHMpCgogICAgIyBTYXZlcyBhbmQgc2tpcHMgaGVhZGVyIHRvIG91dHB1dCBmaWxlCiAgICB3cml0ZXIud3JpdGVyb3cobmV4dChtYXN0ZXIpKQoKICAgICMgU2tpcCBoZWFkZXIgZnJvbSB1cGRhdGVzCiAgICBuZXh0KHVwZGF0ZSkKCiAgICAjIFJlYWQsIHJlbWVtYmVyLCBhbmQgd3JpdGUgdXBkYXRlZCBsaW5lcwogICAgc2VlbiA9IHNldCgpCiAgICBmb3Igcm93IGluIHVwZGF0ZToKICAgICAgICB3cml0ZXIud3JpdGVyb3cocm93KQogICAgICAgIHNlZW4uYWRkKHJvd1snY2FwY29kZSddKQoKICAgIGZvciByb3cgaW4gbWFzdGVyOgogICAgICAgIGlmIHJvd1snY2FwY29kZSddIG5vdCBpbiBzZWVuOgogICAgICAgICAgICB3cml0ZXIud3JpdGVyb3cocm93KQo6CgpweXRob24zIGRlbW8ucHkKCm5sIHJlc3VsdHMuY3N2
1 capcode,discipline,region,location,description,remark
2 000100000,Brandweer,Amsterdam-Amstelland,,banaanProefalarm,
3 000100001,Brandweer,Amsterdam-Amstelland,Aalsmeer,Bevelvoerders,
4 000100004,Brandweer,Amsterdam-Amstelland,Aalsmeer,Korpsalarm,
5 000400001,Brandweer,Groningen,Groningen,Regionaal,Pelotonscommandant Logistiek/Water (Noord)
6 000400002,Brandweer,Groningen,Groningen,,
7 000400003,Brandweer,Groningen,Groningen,Regionaal,Pelotonscommandant Logistiek/Water) (Oost)
8 000100002,Brandweer,Amsterdam-Amstelland,Amsterdam-Amstelland,,Banaanzulu
9 000100003,Brandweer,Amsterdam-Amstelland,Amsterdam-Amstelland,,