Blob Blame History Raw
diff --git a/builtins/evalstring.c b/builtins/evalstring.c
--- a/builtins/evalstring.c
+++ b/builtins/evalstring.c
@@ -431,6 +431,8 @@ parse_and_execute (string, from_file, flags)
 
       if (parse_command () == 0)
 	{
+	  int local_expalias, local_alflag;
+
 	  if ((flags & SEVAL_PARSEONLY) || (interactive_shell == 0 && read_but_dont_execute))
 	    {
 	      last_result = EXECUTION_SUCCESS;
@@ -507,6 +509,19 @@ parse_and_execute (string, from_file, flags)
 		}
 #endif /* ONESHOT */
 
+	      /* We play tricks in the parser and command_substitute() turning
+		 expand_aliases on and off depending on which parsing pass and
+		 whether or not we're in posix mode. This only matters for
+		 parsing, and we let the higher layers deal with that. We just
+		 want to ensure that expand_aliases is set to the appropriate
+		 global value when we go to execute this command, so we save
+		 and restore it around the execution (we don't restore it if
+		 the global value of the flag (expaliases_flag) changes). */
+	      local_expalias = expand_aliases;
+	      local_alflag = expaliases_flag;
+	      if (subshell_environment & SUBSHELL_COMSUB)
+		expand_aliases = expaliases_flag;
+
 	      /* See if this is a candidate for $( <file ). */
 	      if (startup_state == 2 &&
 		  (subshell_environment & SUBSHELL_COMSUB) &&
@@ -524,6 +539,10 @@ parse_and_execute (string, from_file, flags)
 	      dispose_fd_bitmap (bitmap);
 	      discard_unwind_frame ("pe_dispose");
 
+	      /* If the global value didn't change, we restore what we had. */
+	      if ((subshell_environment & SUBSHELL_COMSUB) && local_alflag == expaliases_flag)
+		expand_aliases = local_expalias;
+
 	      if (flags & SEVAL_ONECMD)
 		{
 		  reset_parser ();
diff --git a/command.h b/command.h
--- a/command.h
+++ b/command.h
@@ -114,6 +114,7 @@ enum command_type { cm_for, cm_case, cm_while, cm_if, cm_simple, cm_select,
 #define PF_COMPLETE	0x10	/* same as W_COMPLETE, sets SX_COMPLETE */
 #define PF_EXPANDRHS	0x20	/* same as W_EXPANDRHS */
 #define PF_ALLINDS	0x40	/* array, act as if [@] was supplied */
+#define PF_BACKQUOTE	0x80	/* differentiate `` from $() for command_substitute */
 
 /* Possible values for subshell_environment */
 #define SUBSHELL_ASYNC	0x01	/* subshell caused by `command &' */
diff --git a/parse.y b/parse.y
--- a/parse.y
+++ b/parse.y
@@ -3612,6 +3612,7 @@ tokword:
 #define P_BACKQUOTE	0x0010	/* parsing a backquoted command substitution */
 #define P_ARRAYSUB	0x0020	/* parsing a [...] array subscript for assignment */
 #define P_DOLBRACE	0x0040	/* parsing a ${...} construct */
+#define P_ARITH		0x0080	/* parsing a $(( )) arithmetic expansion */
 
 /* Lexical state while parsing a grouping construct or $(...). */
 #define LEX_WASDOL	0x0001
@@ -3910,6 +3911,9 @@ parse_matched_pair (qc, open, close, lenp, flags)
 	    }
 	  else if ((flags & (P_ARRAYSUB|P_DOLBRACE)) && (tflags & LEX_WASDOL) && (ch == '(' || ch == '{' || ch == '['))	/* ) } ] */
 	    goto parse_dollar_word;
+	  else if ((flags & P_ARITH) && (tflags & LEX_WASDOL) && ch == '(') /*)*/
+	    /* $() inside $(( ))/$[ ] */
+	    goto parse_dollar_word;
 #if defined (PROCESS_SUBSTITUTION)
 	  /* XXX - technically this should only be recognized at the start of
 	     a word */
@@ -3940,7 +3944,7 @@ parse_dollar_word:
 	  else if (ch == '{')		/* } */
 	    nestret = parse_matched_pair (0, '{', '}', &nestlen, P_FIRSTCLOSE|P_DOLBRACE|rflags);
 	  else if (ch == '[')		/* ] */
-	    nestret = parse_matched_pair (0, '[', ']', &nestlen, rflags);
+	    nestret = parse_matched_pair (0, '[', ']', &nestlen, rflags|P_ARITH);
 
 	  CHECK_NESTRET_ERROR ();
 	  APPEND_NESTRET ();
@@ -4079,7 +4083,7 @@ parse_comsub (qc, open, close, lenp, flags)
       peekc = shell_getc (1);
       shell_ungetc (peekc);
       if (peekc == '(')		/*)*/
-	return (parse_matched_pair (qc, open, close, lenp, 0));
+	return (parse_matched_pair (qc, open, close, lenp, P_ARITH));
     }
 
 /*itrace("parse_comsub: qc = `%c' open = %c close = %c", qc, open, close);*/
@@ -4500,7 +4504,7 @@ parse_arith_cmd (ep, adddq)
   int ttoklen;
 
   exp_lineno = line_number;
-  ttok = parse_matched_pair (0, '(', ')', &ttoklen, 0);
+  ttok = parse_matched_pair (0, '(', ')', &ttoklen, P_ARITH);
   rval = 1;
   if (ttok == &matched_pair_error)
     return -1;
@@ -5015,7 +5019,7 @@ read_token_word (character)
 		  pop_delimiter (dstack);
 		}
 	      else
-		ttok = parse_matched_pair (cd, '[', ']', &ttoklen, 0);
+		ttok = parse_matched_pair (cd, '[', ']', &ttoklen, P_ARITH);
 	      if (ttok == &matched_pair_error)
 		return -1;		/* Bail immediately. */
 	      RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 3,
diff --git a/patchlevel.h b/patchlevel.h
--- a/patchlevel.h
+++ b/patchlevel.h
@@ -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 6
+#define PATCHLEVEL 7
 
 #endif /* _PATCHLEVEL_H_ */
diff --git a/subst.c b/subst.c
--- a/subst.c
+++ b/subst.c
@@ -7123,8 +7123,12 @@ command_substitute (string, quoted, flags)
       remove_quoted_escapes (string);
 
       /* We want to expand aliases on this pass if we are not in posix mode
-	 for backwards compatibility. */
-      if (expand_aliases)
+	 for backwards compatibility. parse_and_execute() takes care of
+	 setting expand_aliases back to the global value when executing the
+	 parsed string. We only do this for $(...) command substitution,
+	 since that is what parse_comsub handles; `` comsubs are processed
+	 using parse.y:parse_matched_pair(). */
+      if (expand_aliases && (flags & PF_BACKQUOTE) == 0)
         expand_aliases = posixly_correct == 0;
 
       startup_state = 2;	/* see if we can avoid a fork */
@@ -11292,7 +11296,7 @@ add_string:
 	    else
 	      {
 		de_backslash (temp);
-		tword = command_substitute (temp, quoted, 0);
+		tword = command_substitute (temp, quoted, PF_BACKQUOTE);
 		temp1 = tword ? tword->word : (char *)NULL;
 		if (tword)
 		  dispose_word_desc (tword);
diff --git a/y.tab.c b/y.tab.c
--- a/y.tab.c
+++ b/y.tab.c
@@ -5923,6 +5923,7 @@ tokword:
 #define P_BACKQUOTE	0x0010	/* parsing a backquoted command substitution */
 #define P_ARRAYSUB	0x0020	/* parsing a [...] array subscript for assignment */
 #define P_DOLBRACE	0x0040	/* parsing a ${...} construct */
+#define P_ARITH		0x0080	/* parsing a $(( )) arithmetic expansion */
 
 /* Lexical state while parsing a grouping construct or $(...). */
 #define LEX_WASDOL	0x0001
@@ -6221,6 +6222,9 @@ parse_matched_pair (qc, open, close, lenp, flags)
 	    }
 	  else if ((flags & (P_ARRAYSUB|P_DOLBRACE)) && (tflags & LEX_WASDOL) && (ch == '(' || ch == '{' || ch == '['))	/* ) } ] */
 	    goto parse_dollar_word;
+	  else if ((flags & P_ARITH) && (tflags & LEX_WASDOL) && ch == '(') /*)*/
+	    /* $() inside $(( ))/$[ ] */
+	    goto parse_dollar_word;
 #if defined (PROCESS_SUBSTITUTION)
 	  /* XXX - technically this should only be recognized at the start of
 	     a word */
@@ -6251,7 +6255,7 @@ parse_dollar_word:
 	  else if (ch == '{')		/* } */
 	    nestret = parse_matched_pair (0, '{', '}', &nestlen, P_FIRSTCLOSE|P_DOLBRACE|rflags);
 	  else if (ch == '[')		/* ] */
-	    nestret = parse_matched_pair (0, '[', ']', &nestlen, rflags);
+	    nestret = parse_matched_pair (0, '[', ']', &nestlen, rflags|P_ARITH);
 
 	  CHECK_NESTRET_ERROR ();
 	  APPEND_NESTRET ();
@@ -6390,7 +6394,7 @@ parse_comsub (qc, open, close, lenp, flags)
       peekc = shell_getc (1);
       shell_ungetc (peekc);
       if (peekc == '(')		/*)*/
-	return (parse_matched_pair (qc, open, close, lenp, 0));
+	return (parse_matched_pair (qc, open, close, lenp, P_ARITH));
     }
 
 /*itrace("parse_comsub: qc = `%c' open = %c close = %c", qc, open, close);*/
@@ -6811,7 +6815,7 @@ parse_arith_cmd (ep, adddq)
   int ttoklen;
 
   exp_lineno = line_number;
-  ttok = parse_matched_pair (0, '(', ')', &ttoklen, 0);
+  ttok = parse_matched_pair (0, '(', ')', &ttoklen, P_ARITH);
   rval = 1;
   if (ttok == &matched_pair_error)
     return -1;
@@ -7326,7 +7330,7 @@ read_token_word (character)
 		  pop_delimiter (dstack);
 		}
 	      else
-		ttok = parse_matched_pair (cd, '[', ']', &ttoklen, 0);
+		ttok = parse_matched_pair (cd, '[', ']', &ttoklen, P_ARITH);
 	      if (ttok == &matched_pair_error)
 		return -1;		/* Bail immediately. */
 	      RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 3,