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.

Reply via email to