I have a file with full of key value pairs. I wrote this shell script which reads each line and split key value.
while IFS='=' read -r key value
do
something
done < < application.properties.
One of the property looks like this
Connections/Database/Token=#!VWdg5neXrFiIbMxtAzOwmH+fM2FNtk6QPLhgOHw=
As run my script, its splitting it okay but its ignoring the character =
at the end of the line.
It gives
key = Connections/Database/Token
value = #!VWdg5neXrFiIbMxtAzOwmH+fM2FNtk6QPLhgOHw
but it should be giving like:
key = Connections/Database/Token
value = #!VWdg5neXrFiIbMxtAzOwmH+fM2FNtk6QPLhgOHw=
TL;DR Add an explicit =
to the end of each input line, then remove it from the resulting value before using it.
See https://mywiki.wooledge.org/BashPitfalls#pf47. In short, the =
in IFS is not treated as a field separator, but a field terminator, according to the POSIX definition of field-splitting.
When you write
IFS== read -r key value <<< "foo=var="
the input is first split into two fields, "foo" and "var" (not "foo", "var", and ""). There are exactly as many variables as fields, so you just get key=foo and value=var
If you have
IFS== read -r key value <<< "foo=var=="
now there are three fields: "foo", "var", and "". Because there are only two variables, then key=foo, and value is assigned:
See the POSIX specification for read
for details about each variable to read
is assigned a value after the input undergoes field-splitting.
So, there is never a trailing null field that results from field-splitting the input, only a trailing delimiter that gets added back to the final variable.
To work around this, add an explicit = to your input, and then remove it from the resulting value.
$ for input in "foo=bar" "foo=bar=" "foo=bar=="; do
> IFS== read -r name value <<< "$input="
> echo "${value%=}"
> done
bar
bar=
bar==
In your case, this means using something
while IFS='=' read -r key value
do
value=${value%=}
...
done < < (sed 's/$/=/' application.properties)
Or, as suggested first by Ivan, use parameter expansion operators to split the input instead of let read
do it.
while read -r input; do
key=${input%%=*}
value=${input#*=}
...
done < application.properties
Either way, though, keep in mind that only =
is considered as the delimiter here; you many need to trim trailing whitespace from the key and leading whitespace from the value if your properties look like name = value
rather than name=value
.