On Sun, Jan 12, 2025 at 8:58 AM MacBeth <macbeth.112...@gmail.com> wrote:
> On Sun, Jan 12, 2025 at 8:24 AM Félix Hauri <fe...@f-hauri.ch> wrote: > >> Le Sat, Jan 11, 2025 at 10:49:50AM -0500, Greg Wooledge a écrit : >> > https://mywiki.wooledge.org/BashPitfalls#pf47 >> > "It's a feature." >> > >> -- how do we work around this nonsense? >> >> I've alredy noticed this, but never stictly tested them as: >> >> for row in k{:v1{:v2{:{:{:,},},},:{:{:,},},},:{:{:,},},}; do >> IFS=: read k v <<<"$row"; >> printf "%-20s %s\n" "row='$row'" "k='$k', v='$v'"; >> done >> row='k:v1:v2:::' k='k', v='v1:v2:::' >> row='k:v1:v2::' k='k', v='v1:v2::' >> row='k:v1:v2:' k='k', v='v1:v2:' >> row='k:v1:v2' k='k', v='v1:v2' >> row='k:v1:::' k='k', v='v1:::' >> row='k:v1::' k='k', v='v1::' >> row='k:v1:' k='k', v='v1' >> row='k:v1' k='k', v='v1' >> row='k:::' k='k', v='::' >> row='k::' k='k', v='' >> row='k:' k='k', v='' >> row='k' k='k', v='' >> >> Thanks for driving my attention to this *feature*! >> >> -- >> Félix Hauri - <fe...@f-hauri.ch> - http://www.f-hauri.ch >> >> Greg's link provides a workaround: > > $ input='foo:bar:' > $ echo "$input:" | { IFS=: read -r f1 rest; rest=${rest%:}; declare -p > rest; } > declare -- rest="bar:" > > However it only works for reading a single line. If you want to read a > file, I think `sed` might be worthwhile instead of doing this individually > for every line in a loop. > > Here is a `sed` version: > > delim=, > { > sed -r -e "s/\$/$delim/" | > while IFS="$delim" read -r k values; do > values="${values%$delim}" > echo "k='$k' v='$values'" > done > } <<EOT > a,b,c,d,e > a,b,c,d, > a,b,c,d > a,b,c, > a,b,c > a,b, > a,b > a, > a > EOT > > And here is a version you would have to use without `sed` to get the line > first, before you can append the field terminator to it: > > delim=, > { > while IFS= read -r row; do > IFS="$delim" read -r k values < <(echo "$row$delim") > values="${values%$delim}" > printf "%-20s %s\n" "row='$row'" "k='$k' v='$values'" > done > } <<EOT > a,b,c,d,e > a,b,c,d, > a,b,c,d > a,b,c, > a,b,c > a,b, > a,b > a, > a > EOT > > FYI... * The non-sed version works by setting a blank IFS, preventing 'word splitting', which deactivates bash from possibly mangling the input, so we can then process it however we want to. * Be careful with $delim, it is mainly to show by example, but is not safe for any value... '/' in the `sed` version, for example.