diff -Naurp bash-5.0-orig/bashhist.c bash-5.0/bashhist.c
--- bash-5.0-orig/bashhist.c	2018-07-05 21:41:14.000000000 -0500
+++ bash-5.0/bashhist.c	2020-08-27 22:16:21.275981178 -0500
@@ -560,15 +560,18 @@ pre_process_line (line, print_changes, a
      add that line to the history if ADDIT is non-zero. */
   if (!history_expansion_inhibited && history_expansion && history_expansion_p (line))
     {
+      int old_len;
+
       /* If we are expanding the second or later line of a multi-line
 	 command, decrease history_length so references to history expansions
 	 in these lines refer to the previous history entry and not the
 	 current command. */
+      old_len = history_length;
       if (history_length > 0 && command_oriented_history && current_command_first_line_saved && current_command_line_count > 1)
         history_length--;
       expanded = history_expand (line, &history_value);
       if (history_length >= 0 && command_oriented_history && current_command_first_line_saved && current_command_line_count > 1)
-        history_length++;
+        history_length = old_len;
 
       if (expanded)
 	{
diff -Naurp bash-5.0-orig/bashline.c bash-5.0/bashline.c
--- bash-5.0-orig/bashline.c	2018-11-27 12:20:16.000000000 -0600
+++ bash-5.0/bashline.c	2020-08-27 22:17:56.669051313 -0500
@@ -231,6 +231,7 @@ static int bash_possible_variable_comple
 static int bash_complete_command __P((int, int));
 static int bash_possible_command_completions __P((int, int));
 
+static int completion_glob_pattern __P((char *));
 static char *glob_complete_word __P((const char *, int));
 static int bash_glob_completion_internal __P((int));
 static int bash_glob_complete_word __P((int, int));
@@ -960,11 +961,8 @@ edit_and_execute_command (count, c, edit
       /* This breaks down when using command-oriented history and are not
 	 finished with the command, so we should not ignore the last command */
       using_history ();
-      if (rl_line_buffer[0])
-	{
-	  current_command_line_count++;	/* for rl_newline above */
-	  bash_add_history (rl_line_buffer);
-	}
+      current_command_line_count++;	/* for rl_newline above */
+      bash_add_history (rl_line_buffer);
       current_command_line_count = 0;	/* for dummy history entry */
       bash_add_history ("");
       history_lines_this_session++;
@@ -1741,7 +1739,7 @@ bash_default_completion (text, start, en
 
   /* This could be a globbing pattern, so try to expand it using pathname
      expansion. */
-  if (!matches && glob_pattern_p (text))
+  if (!matches && completion_glob_pattern ((char *)text))
     {
       matches = rl_completion_matches (text, glob_complete_word);
       /* A glob expression that matches more than one filename is problematic.
@@ -1850,7 +1848,7 @@ command_word_completion_function (hint_t
 	  glob_matches = (char **)NULL;
 	}
 
-      globpat = glob_pattern_p (hint_text);
+      globpat = completion_glob_pattern ((char *)hint_text);
 
       /* If this is an absolute program name, do not check it against
 	 aliases, reserved words, functions or builtins.  We must check
@@ -3713,6 +3711,61 @@ bash_complete_command_internal (what_to_
   return bash_specific_completion (what_to_do, command_word_completion_function);
 }
 
+static int
+completion_glob_pattern (string)
+     char *string;
+{
+  register int c;
+  char *send;
+  int open;
+
+  DECLARE_MBSTATE;
+
+  open = 0;
+  send = string + strlen (string);
+
+  while (c = *string++)
+    {
+      switch (c)
+	{
+	case '?':
+	case '*':
+	  return (1);
+
+	case '[':
+	  open++;
+	  continue;
+
+	case ']':
+	  if (open)
+	    return (1);
+	  continue;
+
+	case '+':
+	case '@':
+	case '!':
+	  if (*string == '(')	/*)*/
+	    return (1);
+	  continue;
+
+	case '\\':
+	  if (*string++ == 0)
+	    return (0);	 	  
+	}
+
+      /* Advance one fewer byte than an entire multibyte character to
+	 account for the auto-increment in the loop above. */
+#ifdef HANDLE_MULTIBYTE
+      string--;
+      ADVANCE_CHAR_P (string, send - string);
+      string++;
+#else
+      ADVANCE_CHAR_P (string, send - string);
+#endif
+    }
+  return (0);
+}
+
 static char *globtext;
 static char *globorig;
 
@@ -3877,7 +3930,7 @@ bash_vi_complete (count, key)
       t = substring (rl_line_buffer, p, rl_point);
     }      
 
-  if (t && glob_pattern_p (t) == 0)
+  if (t && completion_glob_pattern (t) == 0)
     rl_explicit_arg = 1;	/* XXX - force glob_complete_word to append `*' */
   FREE (t);
 
diff -Naurp bash-5.0-orig/builtins/evalstring.c bash-5.0/builtins/evalstring.c
--- bash-5.0-orig/builtins/evalstring.c	2018-12-26 10:19:21.000000000 -0600
+++ bash-5.0/builtins/evalstring.c	2020-08-27 22:18:06.723058703 -0500
@@ -91,6 +91,7 @@ should_suppress_fork (command)
   return (startup_state == 2 && parse_and_execute_level == 1 &&
 	  running_trap == 0 &&
 	  *bash_input.location.string == '\0' &&
+	  parser_expanding_alias () == 0 &&
 	  command->type == cm_simple &&
 	  signal_is_trapped (EXIT_TRAP) == 0 &&
 	  signal_is_trapped (ERROR_TRAP) == 0 &&
@@ -100,12 +101,23 @@ should_suppress_fork (command)
 	  ((command->flags & CMD_INVERT_RETURN) == 0));
 }
 
+int
+can_optimize_connection (command)
+     COMMAND *command;
+{
+  return (*bash_input.location.string == '\0' &&
+	  parser_expanding_alias () == 0 &&
+	  (command->value.Connection->connector == AND_AND || command->value.Connection->connector == OR_OR || command->value.Connection->connector == ';') &&
+	  command->value.Connection->second->type == cm_simple);
+}
+
 void
 optimize_fork (command)
      COMMAND *command;
 {
   if (command->type == cm_connection &&
-      (command->value.Connection->connector == AND_AND || command->value.Connection->connector == OR_OR) &&
+      (command->value.Connection->connector == AND_AND || command->value.Connection->connector == OR_OR || command->value.Connection->connector == ';') &&
+      (command->value.Connection->second->flags & CMD_TRY_OPTIMIZING) &&
       should_suppress_fork (command->value.Connection->second))
     {
       command->value.Connection->second->flags |= CMD_NO_FORK;
@@ -280,7 +292,7 @@ parse_and_execute (string, from_file, fl
 
   with_input_from_string (string, from_file);
   clear_shell_input_line ();
-  while (*(bash_input.location.string))
+  while (*(bash_input.location.string) || parser_expanding_alias ())
     {
       command = (COMMAND *)NULL;
 
@@ -412,8 +424,18 @@ parse_and_execute (string, from_file, fl
 		  command->flags |= CMD_NO_FORK;
 		  command->value.Simple->flags |= CMD_NO_FORK;
 		}
-	      else if (command->type == cm_connection)
-		optimize_fork (command);
+
+	      /* Can't optimize forks out here execept for simple commands.
+		 This knows that the parser sets up commands as left-side heavy
+		 (&& and || are left-associative) and after the single parse,
+		 if we are at the end of the command string, the last in a
+		 series of connection commands is
+		 command->value.Connection->second. */
+	      else if (command->type == cm_connection && can_optimize_connection (command))
+		{
+		  command->value.Connection->second->flags |= CMD_TRY_OPTIMIZING;
+		  command->value.Connection->second->value.Simple->flags |= CMD_TRY_OPTIMIZING;
+		}
 #endif /* ONESHOT */
 
 	      /* See if this is a candidate for $( <file ). */
@@ -525,7 +547,7 @@ parse_string (string, from_file, flags,
   ostring = string;
 
   with_input_from_string (string, from_file);
-  while (*(bash_input.location.string))
+  while (*(bash_input.location.string))		/* XXX - parser_expanding_alias () ? */
     {
       command = (COMMAND *)NULL;
 
diff -Naurp bash-5.0-orig/builtins/shopt.def bash-5.0/builtins/shopt.def
--- bash-5.0-orig/builtins/shopt.def	2018-10-05 13:49:02.000000000 -0500
+++ bash-5.0/builtins/shopt.def	2020-08-27 22:16:21.275981178 -0500
@@ -122,7 +122,7 @@ extern int assoc_expand_once;
 extern int array_expand_once;
 #endif
 
-#if defined (SYSLOG_HISTORY) && defined (SYSLOG_SHOPT)
+#if defined (SYSLOG_HISTORY)
 extern int syslog_history;
 #endif
 
diff -Naurp bash-5.0-orig/command.h bash-5.0/command.h
--- bash-5.0-orig/command.h	2018-07-20 20:16:31.000000000 -0500
+++ bash-5.0/command.h	2020-08-27 22:16:21.276981179 -0500
@@ -186,6 +186,7 @@ typedef struct element {
 #define CMD_COPROC_SUBSHELL 0x1000
 #define CMD_LASTPIPE	    0x2000
 #define CMD_STDPATH	    0x4000	/* use standard path for command lookup */
+#define CMD_TRY_OPTIMIZING  0x8000	/* try to optimize this simple command */
 
 /* What a command looks like. */
 typedef struct command {
diff -Naurp bash-5.0-orig/execute_cmd.c bash-5.0/execute_cmd.c
--- bash-5.0-orig/execute_cmd.c	2018-12-05 08:05:14.000000000 -0600
+++ bash-5.0/execute_cmd.c	2020-08-27 22:18:28.724074888 -0500
@@ -564,7 +564,7 @@ execute_command_internal (command, async
   volatile int save_line_number;
 #if defined (PROCESS_SUBSTITUTION)
   volatile int ofifo, nfifo, osize, saved_fifo;
-  volatile char *ofifo_list;
+  volatile void *ofifo_list;
 #endif
 
   if (breaking || continuing)
@@ -750,12 +750,14 @@ execute_command_internal (command, async
   reap_procsubs ();
 #  endif
 
-  if (variable_context != 0)	/* XXX - also if sourcelevel != 0? */
+  /* XXX - also if sourcelevel != 0? */
+  if (variable_context != 0)
     {
       ofifo = num_fifos ();
       ofifo_list = copy_fifo_list ((int *)&osize);
       begin_unwind_frame ("internal_fifos");
-      add_unwind_protect (xfree, ofifo_list);
+      if (ofifo_list)
+	add_unwind_protect (xfree, ofifo_list);
       saved_fifo = 1;
     }
   else
@@ -1099,7 +1101,7 @@ execute_command_internal (command, async
     {
       nfifo = num_fifos ();
       if (nfifo > ofifo)
-	close_new_fifos ((char *)ofifo_list, osize);
+	close_new_fifos ((void *)ofifo_list, osize);
       free ((void *)ofifo_list);
       discard_unwind_frame ("internal_fifos");
     }
@@ -2767,6 +2769,8 @@ execute_connection (command, asynchronou
 	  ((command->value.Connection->connector == OR_OR) &&
 	   (exec_result != EXECUTION_SUCCESS)))
 	{
+	  optimize_fork (command);
+
 	  second = command->value.Connection->second;
 	  if (ignore_return && second)
 	    second->flags |= CMD_IGNORE_RETURN;
diff -Naurp bash-5.0-orig/jobs.c bash-5.0/jobs.c
--- bash-5.0-orig/jobs.c	2018-12-06 10:44:34.000000000 -0600
+++ bash-5.0/jobs.c	2020-08-27 22:16:21.276981179 -0500
@@ -2488,10 +2488,8 @@ wait_for_background_pids ()
     r = wait_for (last_procsub_child->pid);
   wait_procsubs ();
   reap_procsubs ();
-#if 1
+#if 0
   /* We don't want to wait indefinitely if we have stopped children. */
-  /* XXX - should add a loop that goes through the list of process
-     substitutions and waits for each proc in turn before this code. */
   if (any_stopped == 0)
     {
       /* Check whether or not we have any unreaped children. */
@@ -4839,15 +4837,13 @@ void
 end_job_control ()
 {
   if (job_control)
-    {
-      terminate_stopped_jobs ();
+    terminate_stopped_jobs ();
 
-      if (original_pgrp >= 0)
-	give_terminal_to (original_pgrp, 1);
-    }
+  if (original_pgrp >= 0 && terminal_pgrp != original_pgrp)
+    give_terminal_to (original_pgrp, 1);
 
-  if (original_pgrp >= 0)
-    setpgid (0, original_pgrp);
+  if (original_pgrp >= 0 && setpgid (0, original_pgrp) == 0)
+    shell_pgrp = original_pgrp;
 }
 
 /* Restart job control by closing shell tty and reinitializing.  This is
diff -Naurp bash-5.0-orig/lib/glob/glob.c bash-5.0/lib/glob/glob.c
--- bash-5.0-orig/lib/glob/glob.c	2018-09-20 09:53:23.000000000 -0500
+++ bash-5.0/lib/glob/glob.c	2020-08-27 22:16:21.277981180 -0500
@@ -1061,7 +1061,7 @@ glob_filename (pathname, flags)
   char *directory_name, *filename, *dname, *fn;
   unsigned int directory_len;
   int free_dirname;			/* flag */
-  int dflags;
+  int dflags, hasglob;
 
   result = (char **) malloc (sizeof (char *));
   result_size = 1;
@@ -1110,9 +1110,12 @@ glob_filename (pathname, flags)
       free_dirname = 1;
     }
 
+  hasglob = 0;
   /* If directory_name contains globbing characters, then we
-     have to expand the previous levels.  Just recurse. */
-  if (directory_len > 0 && glob_pattern_p (directory_name))
+     have to expand the previous levels.  Just recurse.
+     If glob_pattern_p returns != [0,1] we have a pattern that has backslash
+     quotes but no unquoted glob pattern characters. We dequote it below. */
+  if (directory_len > 0 && (hasglob = glob_pattern_p (directory_name)) == 1)
     {
       char **directories, *d, *p;
       register unsigned int i;
@@ -1175,7 +1178,7 @@ glob_filename (pathname, flags)
       if (d[directory_len - 1] == '/')
 	d[directory_len - 1] = '\0';
 
-      directories = glob_filename (d, dflags);
+      directories = glob_filename (d, dflags|GX_RECURSE);
 
       if (free_dirname)
 	{
@@ -1332,6 +1335,20 @@ only_filename:
 	    free (directory_name);
 	  return (NULL);
 	}
+      /* If we have a directory name with quoted characters, and we are
+	 being called recursively to glob the directory portion of a pathname,
+	 we need to dequote the directory name before returning it so the
+	 caller can read the directory */
+      if (directory_len > 0 && hasglob == 2 && (flags & GX_RECURSE) != 0)
+	{
+	  dequote_pathname (directory_name);
+	  directory_len = strlen (directory_name);
+	}
+
+      /* We could check whether or not the dequoted directory_name is a
+	 directory and return it here, returning the original directory_name
+	 if not, but we don't do that yet. I'm not sure it matters. */
+
       /* Handle GX_MARKDIRS here. */
       result[0] = (char *) malloc (directory_len + 1);
       if (result[0] == NULL)
diff -Naurp bash-5.0-orig/lib/glob/glob.h bash-5.0/lib/glob/glob.h
--- bash-5.0-orig/lib/glob/glob.h	2013-10-28 13:46:12.000000000 -0500
+++ bash-5.0/lib/glob/glob.h	2020-08-27 22:16:21.277981180 -0500
@@ -30,6 +30,7 @@
 #define GX_NULLDIR	0x100	/* internal -- no directory preceding pattern */
 #define GX_ADDCURDIR	0x200	/* internal -- add passed directory name */
 #define GX_GLOBSTAR	0x400	/* turn on special handling of ** */
+#define GX_RECURSE	0x800	/* internal -- glob_filename called recursively */
 
 extern int glob_pattern_p __P((const char *));
 extern char **glob_vector __P((char *, char *, int));
diff -Naurp bash-5.0-orig/lib/glob/glob_loop.c bash-5.0/lib/glob/glob_loop.c
--- bash-5.0-orig/lib/glob/glob_loop.c	2018-12-31 12:35:15.000000000 -0600
+++ bash-5.0/lib/glob/glob_loop.c	2020-08-27 22:16:21.277981180 -0500
@@ -26,10 +26,10 @@ INTERNAL_GLOB_PATTERN_P (pattern)
 {
   register const GCHAR *p;
   register GCHAR c;
-  int bopen;
+  int bopen, bsquote;
 
   p = pattern;
-  bopen = 0;
+  bopen = bsquote = 0;
 
   while ((c = *p++) != L('\0'))
     switch (c)
@@ -54,20 +54,23 @@ INTERNAL_GLOB_PATTERN_P (pattern)
 	continue;
 
       case L('\\'):
-#if 0
 	/* Don't let the pattern end in a backslash (GMATCH returns no match
-	   if the pattern ends in a backslash anyway), but otherwise return 1,
-	   since the matching engine uses backslash as an escape character
-	   and it can be removed. */
-	return (*p != L('\0'));
-#else
-	/* The pattern may not end with a backslash. */
-	if (*p++ == L('\0'))
+	   if the pattern ends in a backslash anyway), but otherwise note that 
+	   we have seen this, since the matching engine uses backslash as an
+	   escape character and it can be removed. We return 2 later if we
+	   have seen only backslash-escaped characters, so interested callers
+	   know they can shortcut and just dequote the pathname. */
+	if (*p != L('\0'))
+	  {
+	    p++;
+	    bsquote = 1;
+	    continue;
+	  }
+	else 	/* (*p == L('\0')) */
 	  return 0;
-#endif
       }
 
-  return 0;
+  return bsquote ? 2 : 0;
 }
 
 #undef INTERNAL_GLOB_PATTERN_P
diff -Naurp bash-5.0-orig/lib/readline/histfile.c bash-5.0/lib/readline/histfile.c
--- bash-5.0-orig/lib/readline/histfile.c	2018-06-11 08:14:52.000000000 -0500
+++ bash-5.0/lib/readline/histfile.c	2020-08-27 22:17:43.895041937 -0500
@@ -305,6 +305,7 @@ read_history_range (const char *filename
   if (file_size == 0)
     {
       free (input);
+      close (file);
       return 0;	/* don't waste time if we don't have to */
     }
 
@@ -368,9 +369,11 @@ read_history_range (const char *filename
     }
 
   has_timestamps = HIST_TIMESTAMP_START (buffer);
-  history_multiline_entries += has_timestamps && history_write_timestamps;  
+  history_multiline_entries += has_timestamps && history_write_timestamps;
 
   /* Skip lines until we are at FROM. */
+  if (has_timestamps)
+    last_ts = buffer;
   for (line_start = line_end = buffer; line_end < bufend && current_line < from; line_end++)
     if (*line_end == '\n')
       {
@@ -379,7 +382,18 @@ read_history_range (const char *filename
 	   line.  We should check more extensively here... */
 	if (HIST_TIMESTAMP_START(p) == 0)
 	  current_line++;
+	else
+	  last_ts = p;
 	line_start = p;
+	/* If we are at the last line (current_line == from) but we have
+	   timestamps (has_timestamps), then line_start points to the
+	   text of the last command, and we need to skip to its end. */
+	if (current_line >= from && has_timestamps)
+	  {
+	    for (line_end = p; line_end < bufend && *line_end != '\n'; line_end++)
+	      ;
+	    line_start = (*line_end == '\n') ? line_end + 1 : line_end;
+	  }
       }
 
   /* If there are lines left to gobble, then gobble them now. */
diff -Naurp bash-5.0-orig/lib/readline/misc.c bash-5.0/lib/readline/misc.c
--- bash-5.0-orig/lib/readline/misc.c	2017-07-07 16:30:12.000000000 -0500
+++ bash-5.0/lib/readline/misc.c	2020-08-27 22:17:21.858025719 -0500
@@ -576,6 +576,7 @@ int
 rl_get_previous_history (int count, int key)
 {
   HIST_ENTRY *old_temp, *temp;
+  int had_saved_line;
 
   if (count < 0)
     return (rl_get_next_history (-count, key));
@@ -588,6 +589,7 @@ rl_get_previous_history (int count, int
     _rl_history_saved_point = (rl_point == rl_end) ? -1 : rl_point;
 
   /* If we don't have a line saved, then save this one. */
+  had_saved_line = _rl_saved_line_for_history != 0;
   rl_maybe_save_line ();
 
   /* If the current line has changed, save the changes. */
@@ -611,7 +613,8 @@ rl_get_previous_history (int count, int
 
   if (temp == 0)
     {
-      rl_maybe_unsave_line ();
+      if (had_saved_line == 0)
+        _rl_free_saved_history_line ();
       rl_ding ();
     }
   else
diff -Naurp bash-5.0-orig/parser.h bash-5.0/parser.h
--- bash-5.0-orig/parser.h	2018-12-28 18:11:18.000000000 -0600
+++ bash-5.0/parser.h	2020-08-27 22:16:21.278981181 -0500
@@ -47,6 +47,7 @@
 #define PST_REPARSE	0x040000	/* re-parsing in parse_string_to_word_list */
 #define PST_REDIRLIST	0x080000	/* parsing a list of redirections preceding a simple command name */
 #define PST_COMMENT	0x100000	/* parsing a shell comment; used by aliases */
+#define PST_ENDALIAS	0x200000	/* just finished expanding and consuming an alias */
 
 /* Definition of the delimiter stack.  Needed by parse.y and bashhist.c. */
 struct dstack {
diff -Naurp bash-5.0-orig/parse.y bash-5.0/parse.y
--- bash-5.0-orig/parse.y	2019-01-02 12:57:34.000000000 -0600
+++ bash-5.0/parse.y	2020-08-27 22:16:21.279981182 -0500
@@ -2557,12 +2557,14 @@ next_alias_char:
   if (uc == 0 && pushed_string_list && pushed_string_list->flags != PSH_SOURCE &&
       pushed_string_list->flags != PSH_DPAREN &&
       (parser_state & PST_COMMENT) == 0 &&
+      (parser_state & PST_ENDALIAS) == 0 &&	/* only once */
       shell_input_line_index > 0 &&
-      shell_input_line[shell_input_line_index-1] != ' ' &&
+      shellblank (shell_input_line[shell_input_line_index-1]) == 0 &&
       shell_input_line[shell_input_line_index-1] != '\n' &&
       shellmeta (shell_input_line[shell_input_line_index-1]) == 0 &&
       (current_delimiter (dstack) != '\'' && current_delimiter (dstack) != '"'))
     {
+      parser_state |= PST_ENDALIAS;
       return ' ';	/* END_ALIAS */
     }
 #endif
@@ -2571,6 +2573,7 @@ pop_alias:
   /* This case works for PSH_DPAREN as well */
   if (uc == 0 && pushed_string_list && pushed_string_list->flags != PSH_SOURCE)
     {
+      parser_state &= ~PST_ENDALIAS;
       pop_string ();
       uc = shell_input_line[shell_input_line_index];
       if (uc)
diff -Naurp bash-5.0-orig/patchlevel.h bash-5.0/patchlevel.h
--- bash-5.0-orig/patchlevel.h	2018-02-21 14:47:15.000000000 -0600
+++ bash-5.0/patchlevel.h	2020-08-27 22:18:38.630082167 -0500
@@ -25,6 +25,6 @@
    regexp `^#define[ 	]*PATCHLEVEL', since that's what support/mkversion.sh
    looks for to find the patch level (for the sccs version string). */
 
-#define PATCHLEVEL 0
+#define PATCHLEVEL 18
 
 #endif /* _PATCHLEVEL_H_ */
diff -Naurp bash-5.0-orig/pathexp.c bash-5.0/pathexp.c
--- bash-5.0-orig/pathexp.c	2018-04-29 16:44:48.000000000 -0500
+++ bash-5.0/pathexp.c	2020-08-27 22:16:21.279981182 -0500
@@ -65,11 +65,11 @@ unquoted_glob_pattern_p (string)
 {
   register int c;
   char *send;
-  int open;
+  int open, bsquote;
 
   DECLARE_MBSTATE;
 
-  open = 0;
+  open = bsquote = 0;
   send = string + strlen (string);
 
   while (c = *string++)
@@ -100,7 +100,14 @@ unquoted_glob_pattern_p (string)
 	   can be removed by the matching engine, so we have to run it through
 	   globbing. */
 	case '\\':
-	  return (*string != 0);
+	  if (*string != '\0' && *string != '/')
+	    {
+	      bsquote = 1;
+	      string++;
+	      continue;
+	    }
+	  else if (*string == 0)
+	    return (0);
 	 	  
 	case CTLESC:
 	  if (*string++ == '\0')
@@ -117,7 +124,8 @@ unquoted_glob_pattern_p (string)
       ADVANCE_CHAR_P (string, send - string);
 #endif
     }
-  return (0);
+
+  return (bsquote ? 2 : 0);
 }
 
 /* Return 1 if C is a character that is `special' in a POSIX ERE and needs to
diff -Naurp bash-5.0-orig/subst.c bash-5.0/subst.c
--- bash-5.0-orig/subst.c	2018-12-22 16:43:37.000000000 -0600
+++ bash-5.0/subst.c	2020-08-27 22:18:38.630082167 -0500
@@ -3625,7 +3625,9 @@ remove_backslashes (string)
    this case, we quote the string specially for the globbing code.  If
    SPECIAL is 2, this is an rhs argument for the =~ operator, and should
    be quoted appropriately for regcomp/regexec.  The caller is responsible
-   for removing the backslashes if the unquoted word is needed later. */   
+   for removing the backslashes if the unquoted word is needed later. In
+   any case, since we don't perform word splitting, we need to do quoted
+   null character removal. */
 char *
 cond_expand_word (w, special)
      WORD_DESC *w;
@@ -3646,6 +3648,8 @@ cond_expand_word (w, special)
     {
       if (special == 0)			/* LHS */
 	{
+	  if (l->word)
+	    word_list_remove_quoted_nulls (l);
 	  dequote_list (l);
 	  r = string_list (l);
 	}
@@ -5108,6 +5112,8 @@ getpattern (value, quoted, expandpat)
 				      (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? Q_PATQUOTE : quoted,
 				      (int *)NULL, (int *)NULL)
 	     : (WORD_LIST *)0;
+  if (l)
+    word_list_remove_quoted_nulls (l);
   pat = string_list (l);
   dispose_words (l);
   if (pat)
@@ -5332,13 +5338,13 @@ clear_fifo_list ()
 {
 }
 
-char *
+void *
 copy_fifo_list (sizep)
      int *sizep;
 {
   if (sizep)
     *sizep = 0;
-  return (char *)NULL;
+  return (void *)NULL;
 }
 
 static void
@@ -5404,8 +5410,13 @@ unlink_fifo_list ()
       for (i = j = 0; i < nfifo; i++)
 	if (fifo_list[i].file)
 	  {
-	    fifo_list[j].file = fifo_list[i].file;
-	    fifo_list[j].proc = fifo_list[i].proc;
+	    if (i != j)
+	      {
+		fifo_list[j].file = fifo_list[i].file;
+		fifo_list[j].proc = fifo_list[i].proc;
+		fifo_list[i].file = (char *)NULL;
+		fifo_list[i].proc = 0;
+	      }
 	    j++;
 	  }
       nfifo = j;
@@ -5421,10 +5432,11 @@ unlink_fifo_list ()
    case it's larger than fifo_list_size (size of fifo_list). */
 void
 close_new_fifos (list, lsize)
-     char *list;
+     void *list;
      int lsize;
 {
   int i;
+  char *plist;
 
   if (list == 0)
     {
@@ -5432,8 +5444,8 @@ close_new_fifos (list, lsize)
       return;
     }
 
-  for (i = 0; i < lsize; i++)
-    if (list[i] == 0 && i < fifo_list_size && fifo_list[i].proc != -1)
+  for (plist = (char *)list, i = 0; i < lsize; i++)
+    if (plist[i] == 0 && i < fifo_list_size && fifo_list[i].proc != -1)
       unlink_fifo (i);
 
   for (i = lsize; i < fifo_list_size; i++)
@@ -5555,22 +5567,22 @@ clear_fifo_list ()
   nfds = 0;
 }
 
-char *
+void *
 copy_fifo_list (sizep)
      int *sizep;
 {
-  char *ret;
+  void *ret;
 
   if (nfds == 0 || totfds == 0)
     {
       if (sizep)
 	*sizep = 0;
-      return (char *)NULL;
+      return (void *)NULL;
     }
 
   if (sizep)
     *sizep = totfds;
-  ret = (char *)xmalloc (totfds * sizeof (pid_t));
+  ret = xmalloc (totfds * sizeof (pid_t));
   return (memcpy (ret, dev_fd_list, totfds * sizeof (pid_t)));
 }
 
@@ -5643,10 +5655,11 @@ unlink_fifo_list ()
    totfds (size of dev_fd_list). */
 void
 close_new_fifos (list, lsize)
-     char *list;
+     void *list;
      int lsize;
 {
   int i;
+  pid_t *plist;
 
   if (list == 0)
     {
@@ -5654,8 +5667,8 @@ close_new_fifos (list, lsize)
       return;
     }
 
-  for (i = 0; i < lsize; i++)
-    if (list[i] == 0 && i < totfds && dev_fd_list[i])
+  for (plist = (pid_t *)list, i = 0; i < lsize; i++)
+    if (plist[i] == 0 && i < totfds && dev_fd_list[i])
       unlink_fifo (i);
 
   for (i = lsize; i < totfds; i++)
diff -Naurp bash-5.0-orig/subst.h bash-5.0/subst.h
--- bash-5.0-orig/subst.h	2018-10-21 17:46:09.000000000 -0500
+++ bash-5.0/subst.h	2020-08-27 22:18:28.724074888 -0500
@@ -273,9 +273,8 @@ extern int num_fifos __P((void));
 extern void unlink_fifo_list __P((void));
 extern void unlink_fifo __P((int));
 
-extern char *copy_fifo_list __P((int *));
-extern void unlink_new_fifos __P((char *, int));
-extern void close_new_fifos __P((char *, int));
+extern void *copy_fifo_list __P((int *));
+extern void close_new_fifos __P((void *, int));
 
 extern void clear_fifo_list __P((void));
 
diff -Naurp bash-5.0-orig/tests/varenv.right bash-5.0/tests/varenv.right
--- bash-5.0-orig/tests/varenv.right	2018-12-17 14:39:48.000000000 -0600
+++ bash-5.0/tests/varenv.right	2020-08-27 22:16:21.280981183 -0500
@@ -146,9 +146,9 @@ declare -x foo="abc"
 inside: declare -x var="value"
 outside: declare -- var="one"
 inside: declare -x var="value"
-outside: declare -x var="value"
-inside: declare -- var="local"
-outside: declare -x var="global"
+outside: declare -- var="outside"
+inside: declare -x var="global"
+outside: declare -- var="outside"
 foo=<unset> environment foo=
 foo=foo environment foo=foo
 foo=foo environment foo=foo
diff -Naurp bash-5.0-orig/variables.c bash-5.0/variables.c
--- bash-5.0-orig/variables.c	2018-12-18 10:07:21.000000000 -0600
+++ bash-5.0/variables.c	2020-08-27 22:16:21.280981183 -0500
@@ -4460,9 +4460,9 @@ char **tempvar_list;
 int tvlist_ind;
 
 /* Take a variable from an assignment statement preceding a posix special
-   builtin (including `return') and create a global variable from it. This
-   is called from merge_temporary_env, which is only called when in posix
-   mode. */
+   builtin (including `return') and create a variable from it as if a
+   standalone assignment statement had been performed. This is called from
+   merge_temporary_env, which is only called when in posix mode. */
 static void
 push_posix_temp_var (data)
      PTR_T data;
@@ -4472,16 +4472,27 @@ push_posix_temp_var (data)
 
   var = (SHELL_VAR *)data;
 
-  binding_table = global_variables->table;
-  if (binding_table == 0)
-    binding_table = global_variables->table = hash_create (VARIABLES_HASH_BUCKETS);
-
-  v = bind_variable_internal (var->name, value_cell (var), binding_table, 0, ASS_FORCE|ASS_NOLONGJMP);
+  /* Just like do_assignment_internal(). This makes assignments preceding
+     special builtins act like standalone assignment statements when in
+     posix mode, satisfying the posix requirement that this affect the
+     "current execution environment." */
+  v = bind_variable (var->name, value_cell (var), ASS_FORCE|ASS_NOLONGJMP);
+
+  /* If this modifies an existing local variable, v->context will be non-zero.
+     If it comes back with v->context == 0, we bound at the global context.
+     Set binding_table appropriately. It doesn't matter whether it's correct
+     if the variable is local, only that it's not global_variables->table */
+  binding_table = v->context ? shell_variables->table : global_variables->table;
 
   /* global variables are no longer temporary and don't need propagating. */
-  var->attributes &= ~(att_tempvar|att_propagate);
+  if (binding_table == global_variables->table)
+    var->attributes &= ~(att_tempvar|att_propagate);
+
   if (v)
-    v->attributes |= var->attributes;
+    {
+      v->attributes |= var->attributes;
+      v->attributes &= ~att_tempvar;	/* not a temp var now */
+    }
 
   if (find_special_var (var->name) >= 0)
     tempvar_list[tvlist_ind++] = savestring (var->name);
@@ -4575,14 +4586,17 @@ dispose_temporary_env (pushf)
      sh_free_func_t *pushf;
 {
   int i;
+  HASH_TABLE *disposer;
 
   tempvar_list = strvec_create (HASH_ENTRIES (temporary_env) + 1);
   tempvar_list[tvlist_ind = 0] = 0;
-    
-  hash_flush (temporary_env, pushf);
-  hash_dispose (temporary_env);
+
+  disposer = temporary_env;
   temporary_env = (HASH_TABLE *)NULL;
 
+  hash_flush (disposer, pushf);
+  hash_dispose (disposer);
+
   tempvar_list[tvlist_ind] = 0;
 
   array_needs_making = 1;
diff -Naurp bash-5.0-orig/y.tab.c bash-5.0/y.tab.c
--- bash-5.0-orig/y.tab.c	2019-01-02 12:57:43.000000000 -0600
+++ bash-5.0/y.tab.c	2020-08-27 22:16:21.281981184 -0500
@@ -4873,12 +4873,14 @@ next_alias_char:
   if (uc == 0 && pushed_string_list && pushed_string_list->flags != PSH_SOURCE &&
       pushed_string_list->flags != PSH_DPAREN &&
       (parser_state & PST_COMMENT) == 0 &&
+      (parser_state & PST_ENDALIAS) == 0 &&	/* only once */
       shell_input_line_index > 0 &&
-      shell_input_line[shell_input_line_index-1] != ' ' &&
+      shellblank (shell_input_line[shell_input_line_index-1]) == 0 &&
       shell_input_line[shell_input_line_index-1] != '\n' &&
       shellmeta (shell_input_line[shell_input_line_index-1]) == 0 &&
       (current_delimiter (dstack) != '\'' && current_delimiter (dstack) != '"'))
     {
+      parser_state |= PST_ENDALIAS;
       return ' ';	/* END_ALIAS */
     }
 #endif
@@ -4887,6 +4889,7 @@ pop_alias:
   /* This case works for PSH_DPAREN as well */
   if (uc == 0 && pushed_string_list && pushed_string_list->flags != PSH_SOURCE)
     {
+      parser_state &= ~PST_ENDALIAS;
       pop_string ();
       uc = shell_input_line[shell_input_line_index];
       if (uc)
