]> git.ipfire.org Git - thirdparty/bash.git/commitdiff
fix a bug in word splitting that could potentially drop the first word; complete...
authorChet Ramey <chet.ramey@case.edu>
Thu, 2 Apr 2026 15:02:52 +0000 (11:02 -0400)
committerChet Ramey <chet.ramey@case.edu>
Thu, 2 Apr 2026 15:02:52 +0000 (11:02 -0400)
14 files changed:
CWRU/CWRU.chlog
assoc.c
builtins/alias.def
builtins/complete.def
builtins/trap.def
builtins/type.def
doc/bash.info
doc/bash.pdf
doc/bashref.info
doc/bashref.texi
parse.y
print_cmd.c
subst.c
subst.h

index fd88c5b1ffaa49fc8dc2d87f3986e3c77d4a1707..9c349e909b7281d23e58843a851cfe402f033836 100644 (file)
@@ -12809,3 +12809,25 @@ lib/glob/glob.c
 doc/bash.1,doc/bashref.texi
        - BASH_REMATCH: update [[ documentation to note that BASH_REMATCH can
          be a local variable
+
+                                  3/20
+                                  ----
+subst.c
+       - word_list_quote_removal,word_list_split: fix initial setting of E
+         on first word split (RESULT == 0). If TRESULT expands to multiple
+         words, all but the first word were dropped because we didn't set
+         E to the end of the TRESULT list
+
+                                  3/30
+                                  ----
+builtins/complete.def
+       - print_cmd_name: prefix command names starting with `-' (however
+         unlikely) with `--'
+         Report from Étienne Barrié <etienne.barrie@gmail.com>
+       - print_cmd_name: use ansic_quote() to quote the command name if
+         necessary
+
+builtins/type.def,builtins/complete.def,builtins/alias.def,builtins/type.def
+print_cmd.c
+       - check for possible $'...' quoting and use it if appropriate instead
+         of just calling sh_single_quote()
diff --git a/assoc.c b/assoc.c
index 8cebfa3ee160b508ac5e1b5a8f27be6af396d53c..d32da4b670b713827299c8a928e931df407a379b 100644 (file)
--- a/assoc.c
+++ b/assoc.c
@@ -616,7 +616,7 @@ assoc_to_string (HASH_TABLE *h, char *sep, int quoted)
 
   l = REVERSE_LIST(list, WORD_LIST *);
 
-  result = l ? string_list_internal (l, sep) : savestring ("");
+  result = l ? string_list_internal (l, sep, 0) : savestring ("");
   dispose_words (l);  
 
   return result;
index 0deb9d34b0e2f3aca8e3285dad13ba493911d944..692f57576607a60f7ee6d420e2d21d91a6ea6d00 100644 (file)
@@ -226,7 +226,10 @@ print_alias (alias_t *alias, int flags)
 {
   char *value;
 
-  value = sh_single_quote (alias->value);
+  if (ansic_shouldquote (alias->value))
+    value = ansic_quote (alias->value, 0, (int *)0);
+  else
+    value = sh_single_quote (alias->value);
   if (flags & AL_REUSABLE)
     printf ("alias %s", (alias->name && alias->name[0] == '-') ? "-- " : "");
   printf ("%s=%s\n", alias->name, value);
index 236cd42c91478fe5608bf933feb1c40d84ca4dc2..1f27152fa8e6c093d72c3ac77505b5f71e3afe5f 100644 (file)
@@ -540,7 +540,15 @@ print_arg (const char *arg, const char *flag, int quote)
 
   if (arg)
     {
-      x = quote ? sh_single_quote (arg) : (char *)arg;
+      if (quote)
+       {
+         if (ansic_shouldquote (arg))
+           x = ansic_quote (arg, 0, (int *)0);
+         else
+           x = sh_single_quote (arg);
+       }
+      else
+       x = (char *)arg;
       printf ("%s %s ", flag, x);
       if (x != arg)
        free (x);
@@ -551,7 +559,10 @@ static void
 print_cmd_name (const char *cmd)
 {
   char *x;
+  char *fmt;
 
+  fmt = (*cmd == '-') ? "-- %s" : "%s";
+  
   if (STREQ (cmd, DEFAULTCMD))
     printf ("-D");
   else if (STREQ (cmd, EMPTYCMD))
@@ -560,14 +571,20 @@ print_cmd_name (const char *cmd)
     printf ("-I");
   else if (*cmd == 0)          /* XXX - can this happen? */
     printf ("''");
+  else if (ansic_shouldquote (cmd))
+    {
+      x = ansic_quote (cmd, 0, (int *)0);
+      printf (fmt, x);
+      free (x);
+    }
   else if (sh_contains_shell_metas (cmd))
     {
       x = sh_single_quote (cmd);
-      printf ("%s", x);
+      printf (fmt, x);
       free (x);
     }
   else
-    printf ("%s", cmd);
+    printf (fmt, cmd);
 }
 
 static int
index f28bde8e87c8dd23886da3f5edb518dc4d16078d..edf183542ed05bd23d438a80b7a9aef3e78d7481 100644 (file)
@@ -301,8 +301,12 @@ showtrap (int i, int show_default)
     }
   else if (signal_is_hard_ignored (i))
     t = (char *)NULL;
-  else
-    t = (p == (char *)IGNORE_SIG) ? (char *)NULL : sh_single_quote (p);
+  else if (p == (char *)IGNORE_SIG)
+    t = (char *)NULL;
+   else if (ansic_shouldquote (p))
+    t = ansic_quote (p, 0, (int *)0);
+   else
+    t = sh_single_quote (p);
 
   sn = signal_name (i);
   /* Make sure that signals whose names are unknown (for whatever reason)
index 6eaa3f03fe704250cd6f8bac5ad6c872d88e9095..8e1931b20df4b70775ea1cef2fff5cb10dd68a54 100644 (file)
@@ -231,7 +231,10 @@ describe_command (char *command, int dflags)
        printf (_("%s is aliased to `%s'\n"), command, alias->value);
       else if (dflags & CDESC_REUSABLE)
        {
-         x = sh_single_quote (alias->value);
+         if (ansic_shouldquote (alias->value))
+           x = ansic_quote (alias->value, 0, (int *)0);
+         else
+           x = sh_single_quote (alias->value);
          printf ("alias %s=%s\n", command, x);
          free (x);
        }
index 697a9454c02902f178bc5a784b51e1943228bab4..474276a5133457f54c2cd11371f8b5d137626c92 100644 (file)
@@ -7265,7 +7265,7 @@ Any variable may be used as an indexed array; the ‘declare’ builtin
 explicitly declares an array.  There is no maximum limit on the size of
 an array, nor any requirement that members be indexed or assigned
 contiguously.  Indexed arrays are referenced using arithmetic
-expressions that must expand to an integer (*note Shell Arithmetic::))
+expressions that must expand to an integer (*note Shell Arithmetic::)
 and are zero-based; associative arrays use arbitrary strings.  Unless
 otherwise noted, indexed array indices must be non-negative integers.
 
@@ -13812,66 +13812,66 @@ Node: Bash Conditional Expressions\7f311088
 Node: Shell Arithmetic\7f316505
 Node: Aliases\7f319832
 Node: Arrays\7f322966
-Node: The Directory Stack\7f330669
-Node: Directory Stack Builtins\7f331466
-Node: Controlling the Prompt\7f335911
-Node: The Restricted Shell\7f338795
-Node: Bash POSIX Mode\7f341888
-Node: Shell Compatibility Mode\7f361704
-Node: Job Control\7f370711
-Node: Job Control Basics\7f371168
-Node: Job Control Builtins\7f377536
-Node: Job Control Variables\7f384324
-Node: Command Line Editing\7f385555
-Node: Introduction and Notation\7f387258
-Node: Readline Interaction\7f389610
-Node: Readline Bare Essentials\7f390798
-Node: Readline Movement Commands\7f392606
-Node: Readline Killing Commands\7f393602
-Node: Readline Arguments\7f395625
-Node: Searching\7f396715
-Node: Readline Init File\7f398958
-Node: Readline Init File Syntax\7f400261
-Node: Conditional Init Constructs\7f427212
-Node: Sample Init File\7f431597
-Node: Bindable Readline Commands\7f434717
-Node: Commands For Moving\7f436255
-Node: Commands For History\7f438719
-Node: Commands For Text\7f444110
-Node: Commands For Killing\7f448235
-Node: Numeric Arguments\7f451023
-Node: Commands For Completion\7f452175
-Node: Keyboard Macros\7f457871
-Node: Miscellaneous Commands\7f458572
-Node: Readline vi Mode\7f466115
-Node: Programmable Completion\7f467092
-Node: Programmable Completion Builtins\7f476828
-Node: A Programmable Completion Example\7f488565
-Node: Using History Interactively\7f493910
-Node: Bash History Facilities\7f494591
-Node: Bash History Builtins\7f498326
-Node: History Interaction\7f505921
-Node: Event Designators\7f510871
-Node: Word Designators\7f512449
-Node: Modifiers\7f514841
-Node: Installing Bash\7f516778
-Node: Basic Installation\7f517894
-Node: Compilers and Options\7f521770
-Node: Compiling For Multiple Architectures\7f522520
-Node: Installation Names\7f524273
-Node: Specifying the System Type\7f526507
-Node: Sharing Defaults\7f527253
-Node: Operation Controls\7f527967
-Node: Optional Features\7f528986
-Node: Reporting Bugs\7f541709
-Node: Major Differences From The Bourne Shell\7f543066
-Node: GNU Free Documentation License\7f564493
-Node: Indexes\7f589670
-Node: Builtin Index\7f590121
-Node: Reserved Word Index\7f597219
-Node: Variable Index\7f599664
-Node: Function Index\7f617077
-Node: Concept Index\7f631210
+Node: The Directory Stack\7f330668
+Node: Directory Stack Builtins\7f331465
+Node: Controlling the Prompt\7f335910
+Node: The Restricted Shell\7f338794
+Node: Bash POSIX Mode\7f341887
+Node: Shell Compatibility Mode\7f361703
+Node: Job Control\7f370710
+Node: Job Control Basics\7f371167
+Node: Job Control Builtins\7f377535
+Node: Job Control Variables\7f384323
+Node: Command Line Editing\7f385554
+Node: Introduction and Notation\7f387257
+Node: Readline Interaction\7f389609
+Node: Readline Bare Essentials\7f390797
+Node: Readline Movement Commands\7f392605
+Node: Readline Killing Commands\7f393601
+Node: Readline Arguments\7f395624
+Node: Searching\7f396714
+Node: Readline Init File\7f398957
+Node: Readline Init File Syntax\7f400260
+Node: Conditional Init Constructs\7f427211
+Node: Sample Init File\7f431596
+Node: Bindable Readline Commands\7f434716
+Node: Commands For Moving\7f436254
+Node: Commands For History\7f438718
+Node: Commands For Text\7f444109
+Node: Commands For Killing\7f448234
+Node: Numeric Arguments\7f451022
+Node: Commands For Completion\7f452174
+Node: Keyboard Macros\7f457870
+Node: Miscellaneous Commands\7f458571
+Node: Readline vi Mode\7f466114
+Node: Programmable Completion\7f467091
+Node: Programmable Completion Builtins\7f476827
+Node: A Programmable Completion Example\7f488564
+Node: Using History Interactively\7f493909
+Node: Bash History Facilities\7f494590
+Node: Bash History Builtins\7f498325
+Node: History Interaction\7f505920
+Node: Event Designators\7f510870
+Node: Word Designators\7f512448
+Node: Modifiers\7f514840
+Node: Installing Bash\7f516777
+Node: Basic Installation\7f517893
+Node: Compilers and Options\7f521769
+Node: Compiling For Multiple Architectures\7f522519
+Node: Installation Names\7f524272
+Node: Specifying the System Type\7f526506
+Node: Sharing Defaults\7f527252
+Node: Operation Controls\7f527966
+Node: Optional Features\7f528985
+Node: Reporting Bugs\7f541708
+Node: Major Differences From The Bourne Shell\7f543065
+Node: GNU Free Documentation License\7f564492
+Node: Indexes\7f589669
+Node: Builtin Index\7f590120
+Node: Reserved Word Index\7f597218
+Node: Variable Index\7f599663
+Node: Function Index\7f617076
+Node: Concept Index\7f631209
 \1f
 End Tag Table
 
index bfbb05a91d1048a35000cd8f38ef8d44c00181a3..84dc06e9057095bae2eb0bb182fe9cef461f47c9 100644 (file)
Binary files a/doc/bash.pdf and b/doc/bash.pdf differ
index 4479e0d69d8695e350d298ecd97569ab6045e909..e437da96374b35560c428dc527435af0b01639e7 100644 (file)
@@ -7266,7 +7266,7 @@ Any variable may be used as an indexed array; the ‘declare’ builtin
 explicitly declares an array.  There is no maximum limit on the size of
 an array, nor any requirement that members be indexed or assigned
 contiguously.  Indexed arrays are referenced using arithmetic
-expressions that must expand to an integer (*note Shell Arithmetic::))
+expressions that must expand to an integer (*note Shell Arithmetic::)
 and are zero-based; associative arrays use arbitrary strings.  Unless
 otherwise noted, indexed array indices must be non-negative integers.
 
@@ -13813,66 +13813,66 @@ Node: Bash Conditional Expressions\7f311295
 Node: Shell Arithmetic\7f316715
 Node: Aliases\7f320045
 Node: Arrays\7f323182
-Node: The Directory Stack\7f330888
-Node: Directory Stack Builtins\7f331688
-Node: Controlling the Prompt\7f336136
-Node: The Restricted Shell\7f339023
-Node: Bash POSIX Mode\7f342119
-Node: Shell Compatibility Mode\7f361938
-Node: Job Control\7f370948
-Node: Job Control Basics\7f371408
-Node: Job Control Builtins\7f377779
-Node: Job Control Variables\7f384570
-Node: Command Line Editing\7f385804
-Node: Introduction and Notation\7f387510
-Node: Readline Interaction\7f389865
-Node: Readline Bare Essentials\7f391056
-Node: Readline Movement Commands\7f392867
-Node: Readline Killing Commands\7f393866
-Node: Readline Arguments\7f395892
-Node: Searching\7f396985
-Node: Readline Init File\7f399231
-Node: Readline Init File Syntax\7f400537
-Node: Conditional Init Constructs\7f427491
-Node: Sample Init File\7f431879
-Node: Bindable Readline Commands\7f435002
-Node: Commands For Moving\7f436543
-Node: Commands For History\7f439010
-Node: Commands For Text\7f444404
-Node: Commands For Killing\7f448532
-Node: Numeric Arguments\7f451323
-Node: Commands For Completion\7f452478
-Node: Keyboard Macros\7f458177
-Node: Miscellaneous Commands\7f458881
-Node: Readline vi Mode\7f466427
-Node: Programmable Completion\7f467407
-Node: Programmable Completion Builtins\7f477146
-Node: A Programmable Completion Example\7f488886
-Node: Using History Interactively\7f494234
-Node: Bash History Facilities\7f494918
-Node: Bash History Builtins\7f498656
-Node: History Interaction\7f506254
-Node: Event Designators\7f511207
-Node: Word Designators\7f512788
-Node: Modifiers\7f515183
-Node: Installing Bash\7f517123
-Node: Basic Installation\7f518242
-Node: Compilers and Options\7f522121
-Node: Compiling For Multiple Architectures\7f522874
-Node: Installation Names\7f524630
-Node: Specifying the System Type\7f526867
-Node: Sharing Defaults\7f527616
-Node: Operation Controls\7f528333
-Node: Optional Features\7f529355
-Node: Reporting Bugs\7f542081
-Node: Major Differences From The Bourne Shell\7f543441
-Node: GNU Free Documentation License\7f564871
-Node: Indexes\7f590051
-Node: Builtin Index\7f590505
-Node: Reserved Word Index\7f597606
-Node: Variable Index\7f600054
-Node: Function Index\7f617470
-Node: Concept Index\7f631606
+Node: The Directory Stack\7f330887
+Node: Directory Stack Builtins\7f331687
+Node: Controlling the Prompt\7f336135
+Node: The Restricted Shell\7f339022
+Node: Bash POSIX Mode\7f342118
+Node: Shell Compatibility Mode\7f361937
+Node: Job Control\7f370947
+Node: Job Control Basics\7f371407
+Node: Job Control Builtins\7f377778
+Node: Job Control Variables\7f384569
+Node: Command Line Editing\7f385803
+Node: Introduction and Notation\7f387509
+Node: Readline Interaction\7f389864
+Node: Readline Bare Essentials\7f391055
+Node: Readline Movement Commands\7f392866
+Node: Readline Killing Commands\7f393865
+Node: Readline Arguments\7f395891
+Node: Searching\7f396984
+Node: Readline Init File\7f399230
+Node: Readline Init File Syntax\7f400536
+Node: Conditional Init Constructs\7f427490
+Node: Sample Init File\7f431878
+Node: Bindable Readline Commands\7f435001
+Node: Commands For Moving\7f436542
+Node: Commands For History\7f439009
+Node: Commands For Text\7f444403
+Node: Commands For Killing\7f448531
+Node: Numeric Arguments\7f451322
+Node: Commands For Completion\7f452477
+Node: Keyboard Macros\7f458176
+Node: Miscellaneous Commands\7f458880
+Node: Readline vi Mode\7f466426
+Node: Programmable Completion\7f467406
+Node: Programmable Completion Builtins\7f477145
+Node: A Programmable Completion Example\7f488885
+Node: Using History Interactively\7f494233
+Node: Bash History Facilities\7f494917
+Node: Bash History Builtins\7f498655
+Node: History Interaction\7f506253
+Node: Event Designators\7f511206
+Node: Word Designators\7f512787
+Node: Modifiers\7f515182
+Node: Installing Bash\7f517122
+Node: Basic Installation\7f518241
+Node: Compilers and Options\7f522120
+Node: Compiling For Multiple Architectures\7f522873
+Node: Installation Names\7f524629
+Node: Specifying the System Type\7f526866
+Node: Sharing Defaults\7f527615
+Node: Operation Controls\7f528332
+Node: Optional Features\7f529354
+Node: Reporting Bugs\7f542080
+Node: Major Differences From The Bourne Shell\7f543440
+Node: GNU Free Documentation License\7f564870
+Node: Indexes\7f590050
+Node: Builtin Index\7f590504
+Node: Reserved Word Index\7f597605
+Node: Variable Index\7f600053
+Node: Function Index\7f617469
+Node: Concept Index\7f631605
 \1f
 End Tag Table
 
index edeb163796293ee23310569e3ae08cca3e8c73ed..079a5b2638eb50c272402de7634ebf5b6e337f8c 100644 (file)
@@ -8704,7 +8704,7 @@ There is no maximum
 limit on the size of an array, nor any requirement that members
 be indexed or assigned contiguously.
 Indexed arrays are referenced using arithmetic expressions
-that must expand to an integer (@pxref{Shell Arithmetic}))
+that must expand to an integer (@pxref{Shell Arithmetic})
 and are zero-based;
 associative arrays use arbitrary strings.
 Unless otherwise noted, indexed array indices must be non-negative integers.
diff --git a/parse.y b/parse.y
index fd0d7ff3d37f01b557d9c01b8de7a60ea04c2e46..2e285d56e63eb812d47489f4496f187298cde819 100644 (file)
--- a/parse.y
+++ b/parse.y
@@ -6782,7 +6782,7 @@ error_token_from_token (int tok)
       break;
     case ARITH_FOR_EXPRS:
       if (yylval.word_list)
-       t = string_list_internal (yylval.word_list, " ; ");
+       t = string_list_internal (yylval.word_list, " ; ", 0);
       break;
     case COND_CMD:
       t = (char *)NULL;                /* punt */
index a955d4141a79ff09a843ad38db18265365368042..3698418a6e719819cc1d133e7c51ff84b46d52be 100644 (file)
@@ -1132,7 +1132,10 @@ print_heredoc_header (REDIRECT *redirect)
   /* If the here document delimiter is quoted, single-quote it. */
   if (redirect->redirectee.filename->flags & W_QUOTED)
     {
-      x = sh_single_quote (redirect->here_doc_eof);
+      if (ansic_shouldquote (redirect->here_doc_eof))
+       x = ansic_quote (redirect->here_doc_eof, 0, (int *)0);
+      else
+       x = sh_single_quote (redirect->here_doc_eof);
       cprintf ("<<%s%s", kill_leading ? "-" : "", x);
       free (x);
     }
diff --git a/subst.c b/subst.c
index db4ed43a786a2595168554031bf49b0fa836ac86..5f95a2784e94105b62b6515f248fc4bdc1782ec6 100644 (file)
--- a/subst.c
+++ b/subst.c
@@ -2851,7 +2851,7 @@ assignment_name (const char *string)
 /* Return a single string of all the words in LIST.  SEP is the separator
    to put between individual elements of LIST in the output string. */
 char *
-string_list_internal (WORD_LIST *list, char *sep)
+string_list_internal (WORD_LIST *list, char *sep, int flags)
 {
   register WORD_LIST *t;
   char *result, *r;
@@ -2904,7 +2904,7 @@ string_list_internal (WORD_LIST *list, char *sep)
 char *
 string_list (WORD_LIST *list)
 {
-  return (string_list_internal (list, " "));
+  return (string_list_internal (list, " ", 0));
 }
 
 /* An external interface that can be used by the rest of the shell to
@@ -2982,7 +2982,7 @@ string_list_dollar_star (WORD_LIST *list, int quoted, int flags)
   sep[1] = '\0';
 #endif
 
-  ret = string_list_internal (list, sep);
+  ret = string_list_internal (list, sep, 0);
 #if defined (HANDLE_MULTIBYTE) && !defined (__GNUC__)
   free (sep);
 #endif
@@ -3064,7 +3064,7 @@ string_list_dollar_at (WORD_LIST *list, int quoted, int flags)
                ? quote_list (list)
                : list_quote_escapes (list);
 
-  ret = string_list_internal (tlist, sep);
+  ret = string_list_internal (tlist, sep, 0);
 #if defined (HANDLE_MULTIBYTE) && !defined (__GNUC__)
   free (sep);
 #endif
@@ -8179,7 +8179,7 @@ parameter_brace_expand_rhs (char *name, char *value,
          string_list_dollar_star for "$@" otherwise. */
       if (l->next && ifs_is_null)
        {
-         temp = string_list_internal (l, " ");
+         temp = string_list_internal (l, " ", 0);
          w->flags |= W_SPLITSPACE;
        }
       else if (l_hasdollat || l->next)
@@ -12452,11 +12452,10 @@ word_list_quote_removal (WORD_LIST *list, int quoted)
       if (result == 0)
        result = e = tresult;
       else
-       {
-         e->next = tresult;
-         while (e->next)
-           e = e->next;
-       }
+       e->next = tresult;
+
+      while (e && e->next)
+       e = e->next;
     }
   return (result);
 }
@@ -12584,11 +12583,10 @@ word_list_split (WORD_LIST *list)
       if (result == 0)
         result = e = tresult;
       else
-       {
-         e->next = tresult;
-         while (e->next)
-           e = e->next;
-       }
+       e->next = tresult;
+
+      while (e && e->next)
+       e = e->next;
     }
   return (result);
 }
diff --git a/subst.h b/subst.h
index 69f966e92f9accbdcaf13d8b99a7313cbfe77df9..b6f0df9d2e898549b9ea6259e2fa2893d135a863 100644 (file)
--- a/subst.h
+++ b/subst.h
@@ -118,7 +118,7 @@ extern char *assignment_name (const char *);
 
 /* Return a single string of all the words present in LIST, separating
    each word with SEP. */
-extern char *string_list_internal (WORD_LIST *, char *);
+extern char *string_list_internal (WORD_LIST *, char *, int);
 
 /* Return a single string of all the words present in LIST, separating
    each word with a space. */