Reputation: 314
i have a bunch of conf files, which can be described as two types:
Type 1 (Typical conf-file-like ini files):
[server]
# Protocol (http, https)
;protocol = http
# The ip address to bind to, empty will bind to all interfaces
;http_addr = 192.168.33.2
# The http port to use
;http_port = 3000
Type 2 (malformated conf file):
###
### [http]
###
[http]
# Determines whether HTTP endpoint is enabled.
# enabled = true
# The bind address used by the HTTP service.
# bind-address = ":8080"
For Type1 conf files, i successfully could use tools like crudini p.a with crudini --set filename.conf server protocol https
which actually adds a new entry under server section instead of uncommenting the existing. As long it works its ok.
crudini failes with Type 2 files with a parse error, because the conf file is not a proper ini file. For these i tried using sed but failed.
What i want to achieve is to use one script/tool to be able to modify both type of files. Maybe a good approach could be to:
;
or #
and section name;
or #
, replace the complete line (this also gets rid of the white spaces and inserts it at same position)I found a lot of scripts, with a lot of code for this, but need a small footprint solution working with Docker conf files.
Can you help me to find a elegant solution for this?
Upvotes: 0
Views: 620
Reputation: 24466
Here. Pay it forward. The leg work is handled by gawk. I tested it with the --posix
switch, so I think it should work with mawk and other awk variants as well.
The script will quote values containing spaces and equal signs, and values where the value being replaced was quoted. I'm not familiar with Docker files, but since ":8000" was quoted in your second example I thought the quoting might be important.
#!/bin/bash
usage() {
echo "Usage: $(basename $0) -s section -i item -v value filename"
exit
}
export LC_ALL=C
while getopts "s:i:v:" i || (( $# )); do {
case $i in
s) section="$OPTARG";;
i) item="$OPTARG";;
v) value="$OPTARG";;
?) [[ -f $1 ]] && filename="$1";shift;;
esac
}; done
[[ -z "$section" ]] || [[ -z "$item" ]] || [[ -z "$filename" ]] && usage
[[ -w "$filename" ]] && {
tmpfile="$(mktemp -p /dev/shm)"
[[ $(whoami) = "root" ]] && chown --reference="$filename" "$tmpfile"
chmod --reference="$filename" "$tmpfile"
} || {
echo "Invalid filename: $filename"
usage
}
cleanup() {
[[ -f "$tmpfile" ]] && rm -f "$tmpfile"
exit
}
trap cleanup EXIT
awk -v section="$section" -v item="$item" -v value="$value" '
function quote(str) { return "\"" str "\"" }
/^\[[^\]]+\]/ {
if (flag) {
printf "%s = %s\n", item, value ~ /[[:space:]=]/ ? quote(value) : value
flag = 0
}
else flag = (section == substr($0, 2, index($0, "]") - 2))
}
$0 ~ ("^[[:space:]#;]*" item "[[:space:]]*=") {
if (flag) {
$0 = sprintf("%s = %s", item, /"/ || value ~ /[[:space:]=]/ ? quote(value) : value)
flag = 0
}
}
1
END { if (flag) printf "%s = %s", item, value ~ /[[:space:]=]/ ? quote(value) : value }
' "$filename" >"$tmpfile"
[[ -s "$tmpfile" ]] && mv "$tmpfile" "$filename" || echo "Something went horribly wrong."
Upvotes: 2