Reputation: 36021
I have several configuration files with configurable data within them. Example (look at ${ConnectorPort}
):
<Connector port="${ConnectorPort}" protocol="HTTP/1.1" server="MyServer"
connectionTimeout="20000"
redirectPort="8443"
URIEncoding="UTF-8"/>
In config time, I'd like to replace the keys with the values from a given properties file.
The problem is that it takes a long time (a few seconds per file) to iterate over all the files and iterate over all the properties to check for replacement for each property. Script below.
Any idea how to do it faster using bash?
Perhaps there's a way in sed or awk to get all properties as a single input?
Perhaps do the replacement in memory?
Script:
for file in "${files[@]}"
do
# echo ------
#echo In file: $file
#echo ------
cp -f "$file" "$file.bak"
unset replaced
for prop in "${!props[@]}"
do
key="$prop"
keyToReplace="\${$prop}"
val="${props[$key]}"
# echo In prop: $key=$val
sed -i "s|$keyToReplace|$val|Igw $file.change" "$file"
assertReturnStatus $? "sed failed"
if [ -z "$replaced" ] && [ -s "$file.change" ]; then
replaced=true
echo Replacing props in file "$file"
cp -n "$file.bak" "$file.orig"
fi
done
rm -f "$file.change"
rm -f "$file.bak"
done
* One of the requirements is to create a backup (.orig) if a file is changed.
Thanks.
Upvotes: 0
Views: 1152
Reputation: 36021
An in-memory solution, reading the content to memory and doing the replacement in memory:
for file in "${files[@]}"
do
# echo ------
# echo In file: $file
# echo ------
unset replaced
contentOrig=`cat "$file"`
content="$contentOrig"
for prop in "${!props[@]}"
do
# No need to search for all properties if there are
if [[ ! "$content" == *'${'* ]]; then
break
fi
key="$prop"
keyToReplace="\${$prop}"
val="${props[$key]}"
# echo In prop: $key=$val
content="${content//$keyToReplace/$val}"
assertReturnStatus $? "sed failed"
done
# TODO: Show warning if `${` still exists (Excluding `*.sh` files). We might have forgotten to add a property.
if [[ "$content" != "$contentOrig" ]]; then
let "filesReplacedCount++"
cp -n "$file" "$file.orig"
echo "$content" > "$file"
echo Replaced props in file "$file"
fi
done
Upvotes: 0
Reputation: 842
Your loop inside the loop causes sed
to run multiple times for each file. So, get rid of the loop inside the loop.
declare -a sedArgs
for prop in "${!props[@]}"
do
key="$prop"
keyToReplace="\${$prop}"
val="${props[$key]}"
# echo In prop: $key=$val
#sed -i "s|$keyToReplace|$val|Igw $file.change" "$file"
sedArgs+=("-e")
sedArgs+=("s|$keyToReplace|$val|Ig")
done
for file in "${files[@]}"
do
# echo ------
#echo In file: "$file"
#echo ------
sed -i.orig "${sedArgs[@]}" $file
cmp -s "$file" "${file}.orig" && mv "${file}.orig" "$file"
done
Upvotes: 1