On 9 February 2017 at 20:55, Chet Ramey <[email protected]> wrote:
> On 2/8/17 3:04 PM, Conor McCarthy wrote:
>
>> Bash Version: 4.4
>> Patch Level: 12
>> Release Status: release
>>
>> Description:
>> Here strings are documented as:
>>
>> [n]<<<word
>>
>> The word undergoes brace expansion, tilde expansion, parameter
>> and
>> variable expansion, command substitution, arithmetic expansion,
>> and
>> quote removal.
>>
>> But brace expansion is not applied:
>>
>> $ read zz <<< {1..9}
>> $ echo $zz
>> {1..9}
>>
>> The codepath from write_here_string() does not pass through any
>> expand_xxx functions which apply brace expansion, AFAICT.
>>
>> (bash was built with -fno-inline for gdb only)
>>
>> Repeat-By:
>> $ read zz <<< {1..9}
>> $ echo $zz
>> {1..9}
>>
>> Expected behaviour would be similar to:
>> $ read zz <<< $(echo {1..9})
>> $ echo $zz
>> 1 2 3 4 5 6 7 8 9
>
> Thanks for the report. This is a documentation error. Your workaround
> is a reasonable one.
Diff attached for the curious. Consider this towards the Dr. Bunsen end
of the experimental spectrum, I'm a relative novice with bash internals.
I can't think of a compelling use case, but it does allow stupid loopless
and subshell-less tricks like:
read az[{65..90}] <<< {A..Z}
and can be (ab)used for shorthand array slice type operation:
read aa[{1..5}] <<< "${az[" {69..65} "]}"
(though the absence of parameterisation for {..} makes it less useful
than it might initially appear)
Case closed, thanks!
Regards,
Conor.
--- redir.c.orig 2017-02-08 16:48:26.000000000 +0000
+++ redir.c 2017-02-13 18:39:34.000000000 +0000
@@ -320,12 +320,36 @@
{
char *herestr;
int herelen, n, e, old;
+ char *expword=redirectee->word;
+#if defined(BRACE_EXPANSION)
+ int eindex;
+
+ char **expansions=brace_expand(redirectee->word);
+ char *temp_string;
+ WORD_DESC *w;
+
+ /* the iter/free logic copied from brace_expand_word_list() */
+ WORD_LIST * output_list=NULL;
+ for (eindex = 0; temp_string = expansions[eindex]; eindex++)
+ {
+ w = alloc_word_desc ();
+ w->word = expansions[eindex];
+ //w->flags = 0;
+ w = make_word_flags(w, expansions[eindex]);
+ output_list= make_word_list (w, output_list);
+ }
+ free(expansions);
+ if (output_list) output_list= REVERSE_LIST (output_list, WORD_LIST *);
+ expword=string_list(output_list); /* join with " " */
+ dispose_words(output_list);
+
+#endif
expanding_redir = 1;
/* Now that we've changed the variable search order to ignore the temp
environment, see if we need to change the cached IFS values. */
sv_ifs ("IFS");
- herestr = expand_string_unsplit_to_string (redirectee->word, 0);
+ herestr = expand_string_unsplit_to_string (expword, 0);
expanding_redir = 0;
/* Now we need to change the variable search order back to include the temp
environment. We force the temp environment search by forcing
@@ -336,6 +360,10 @@
sv_ifs ("IFS");
executing_builtin = old;
+#if defined(BRACE_EXPANSION)
+ free(expword);
+#endif
+
herelen = STRLEN (herestr);
n = write (fd, herestr, herelen);