Say I have the file foo.txt
"The" "quick brown" "fox" "jumps over" "the" "lazy dog."
I would like to read these "fields" from the file into an array. However my attempt is failing if the field has a space
$ read -a bar < foo.txt
$ echo ${bar[0]}
"The"
$ echo ${bar[1]}
"quick
I have seen answers suggest changing IFS
, but this is a single line so that would appear not to help.
Here's a function that will do the job. It might be slow for huge strings, but will do the job all right, with no caveats like arbitrary code execution or path name expansion:
#!/bin/bash
parse_quoted_items() {
# Return array is parse_quoted_items_ary
local line=$1
parse_quoted_items_ary=() parse_quoted_items_error=
while [[ $line ]]; do
if [[ $line =~ ^[[:space:]]*\"([^\"]*)\"([[:space:]]+.+|)[[:space:]]*$ ]]; then
parse_quoted_items_ary+=( "${BASH_REMATCH[1]}" )
line=${BASH_REMATCH[2]}
else
parse_quoted_items_error=$line
return 1
fi
done
}
Then you can use as
IFS= read -r line < foo.txt
if parse_quoted_items "$line"; do
declare -p parse_quoted_items_ary
else
printf >&2 "There was an error parsing the string at %s\n" "$parse quoted_items_error"
exit 1
fi
This is not a satisfactory answer, but I doubt there are any (safe) ways that don't explicitly parse the string.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With