How to make bash built-in "read" ignore commented or empty lines?
You don't need a tempfile to do this, and sed (or awk) are far more flexible in comment processing than a shell case statement.
For example:
configfile='/opt/myconfigfile.txt'
[ $# -gt 0 ] && [ -r "$1" ] && configfile="$1"
sed -e 's/[[:space:]]*#.*// ; /^[[:space:]]*$/d' "$configfile" |
while read var1 var2 var3 var4; do
# stuff with var1, etc.
done
This strips comments (with or without leading whitespace) and deletes empty lines from the input before piping it into the while loop. It handles comments on lines by themselves and comments appended to the end of the line:
# full-line comment
# var1 var2 var3 var4
abc 123 xyz def # comment here
Calling sed
or awk
for tasks like this isn't "absurd", it's perfectly normal. That's what these tools are for. As for performance, I'd bet that in anything but very tiny input files, the sed
version would be much faster. Piping to sed
has some startup overhead but runs very fast, while shell is slow.
This works because read
breaks everything on whitespace (IFS), so if var1 is empty or starts with '#', then skip it.
while read var1 var2 var3 var4; do
case $var1 in
''|\#*) continue ;; # skip blank lines and lines starting with #
esac
echo "var1: '$var1'"
# stuff with var1, etc.
done < "${1:-default_config_file}"
Then input has to be redirected into the loop instead of to the while
command list. The "${1:-default_config_file}"
expands to the first command line parameter if not empty, otherwise expands to default_config_file
you can also use variable expansion, etc in the default value string.
Because you're interested in minimizing pre-processing, I think this is equivalent, but also removes all comments:
while read line; do
echo "${line%%#*}" | {
read var1 var2 var3 var4
[ -z "$var1" ] && continue
# stuff with var1, etc.
for i in 1 2 3 4; do eval echo "\"var$i: \$var$i\""; done #debug only!
}
done < "${1:-default_config_file}"
This uses the shell parameter expansion substring processing feature. ${line%%#*}
expands to the original value of line
except the first #
and everything after it are removed. Load that into var1-4
and continue as usual. The test to continue
shortens because we now only need to check for empty string, not #
.