seanoshea
seanoshea

Reputation: 6136

properties file search and replace

I've got two properties files and I'd like to replace key/value pairs in File A with any matching key/value entries in File B. File A will have more entries than File B - it's not expected that the two files will have the exact same number of entries. Also, File B might have entries which are not included in File A.

As an example:

File A
"GB" = "United Kingdom";
"SE" = "Sweden";
"BR" = "Brazil";
"FR" = "France";
"ES" = "Spain";
"DE" = "Germany";

File B
"GB" = "Regno Unito";
"SE" = "Svezia";
"BR" = "Brasile";
"BR" = "Brasile";
"CL" = "Cile";

Desired Result
"GB" = "Regno Unito";
"SE" = "Svezia";
"BR" = "Brasile";
"FR" = "France";
"ES" = "Spain";
"DE" = "Germany";
"CL" = "Cile";

Is it possible to execute this search and replace using bash?

Thanks,

Sean

Upvotes: 0

Views: 535

Answers (2)

Steve
Steve

Reputation: 54512

Here's one way using GNU awk:

awk -F " = " 'FNR==NR { array[$1]=$2; next } $1 in array { sub ($2, array[$1]) }1' fileb filea

Results:

"GB" = "Regno Unito";
"SE" = "Svezia";
"BR" = "Brasile";
"FR" = "France";
"ES" = "Spain";
"DE" = "Germany";

EDIT:

You can simply delete the array elements after a substitution has occurred. Then at the end of the script, print out what's left:

awk -F " = " 'FNR==NR { array[$1]=$2; next } $1 in array { sub ($2, array[$1]); delete array[$1] }1; END { for (i in array) print i FS array[i] }' fileb filea

Results:

"GB" = "Regno Unito";
"SE" = "Svezia";
"BR" = "Brasile";
"FR" = "France";
"ES" = "Spain";
"DE" = "Germany";
"CL" = "Cile";

Upvotes: 2

ghoti
ghoti

Reputation: 46856

The following bash-only script will spit out the results you're asking for:

#!/bin/bash

# Identify our files. If you want, test for their existence before proceeding.
fileA="$1"
fileB="$2"

# Define an associated array
declare -A countries

# Read our initial data
while read cc junk name; do
 if [[ -n "$cc" ]]; then
   countries["$cc"]="$name"
 fi
done < "$fileA"

# Overwrite array elements with updated values
while read cc junk name; do
 if [[ -n "$cc" ]]; then
   countries["$cc"]="$name"
 fi
done < "$fileB"

# Print the results
for cc in "${!countries[@]}"; do
  echo "$cc = ${countries[$cc]}"
done

The results won't be in exactly the same order, but I suspect that isn't important. If it is, you can create an additional array whose index is a counter, then instead of the final for cc in ..., you can simply walk through that array to get the $countries indices in the right order. Let me know if that's important and you can't figure it out.

I only post this here because you asked for a bash solution. Steve's awk script is much more succinct, and probably a lot faster. (Just guessing. It probably isn't even worth the time to benchmark it.)

Upvotes: 1

Related Questions