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);

Reply via email to