[prev in list] [next in list] [prev in thread] [next in thread] 

List:       bash-bug
Subject:    Re: Strange compgen behaviour
From:       "Bernd.Eggink" <monoped () sudrala ! de>
Date:       2009-09-25 20:42:55
Message-ID: 4ABD2B4F.4090204 () sudrala ! de
[Download RAW message or body]

Chet Ramey schrieb:
> Bernd Eggink wrote:
>> Chet Ramey schrieb:
>>>> Hm, compgen appears to behave strange if words contain whitespace. 
>>> Well, it splits the argument to -W on $IFS as documented.  What other
>>> strange behavior do you see? 
>> For example, this:
>>
>>     function _aha
>>     {
>>         local list="a b:c d:e f"
>>         COMPREPLY=($(IFS=: compgen -W "$list"))
>>     }
>>
>>     complete -F _aha aha
>>
>> Typing aha <Tab> cycles through 6 items a, b, c, d, e, f, whereas I
>> would expect 3 items 'a b', 'c d', 'e f'. It looks like compgen splits
>> the argument to -W on $IFS _and_ whitespace. Or am I missing something?
> 
> I don't think you're considering the interaction between compgen,
> command substitution, and compound array assignment.
> 
> I'll use the assignment to `list' you used above for the explanation.
> 
> compgen performs word splitting using $IFS and then outputs the results,
> one word per line:
> 
> $ IFS=: compgen -W "$list"
> a b
> c d
> e f
> 
> Command substitution takes that, chops off the last newline, and, since
> it's unquoted, performs word splitting using $IFS on the result:
> 
> $ recho $(IFS=: compgen -W "$list")
> argv[1] = <a>
> argv[2] = <b>
> argv[3] = <c>
> argv[4] = <d>
> argv[5] = <e>
> argv[6] = <f>
> 
> If you want to preserve the embedded newlines, you have to quote the
> expansion (but see below):
> 
> $ recho "$(IFS=: compgen -W "$list")"
> argv[1] = <a b^Jc d^Je f>
> 
> When performing compound array assignments, though, the words between
> the parens undergo all the shell word expansions, including word splitting:
> 
> $ COMPREPLY=( $(IFS=: compgen -W "$list") )
> $ recho "${COMPREPLY[@]}"
> argv[1] = <a>
> argv[2] = <b>
> argv[3] = <c>
> argv[4] = <d>
> argv[5] = <e>
> argv[6] = <f>
> 
> So you can split on just the embedded newlines by setting $IFS:
> 
> $ oifs="$IFS"
> $ IFS=$'\n' COMPREPLY=( $(IFS=: compgen -W "$list") )
> $ IFS="$oifs"
> $ recho "${COMPREPLY[@]}"
> argv[1] = <a b>
> argv[2] = <c d>
> argv[3] = <e f>
> 
> Remember to save and restore $IFS, though, since the assignment to it
> preceding the assignment to COMPREPLY will persist.

Chet,

thanks for the clarification. It's actually quite obvious and I should 
have seen it myself.

Regards,
Bernd



[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic