On 9 February 2017 at 20:55, Chet Ramey <chet.ra...@case.edu> 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);