@@ -699,7 +699,14 @@ pub fn eval_expression_with_input(
699699 }
700700 } ;
701701
702- Ok ( might_consume_external_result ( input) )
702+ // Note: for `table` command, it mights returns `ExternalStream with stdout`
703+ // whatever `redirect_output` is true or false, so we only want to consume ExternalStream
704+ // if relative stdout is None.
705+ if let PipelineData :: ExternalStream { stdout : None , .. } = input {
706+ Ok ( might_consume_external_result ( input) )
707+ } else {
708+ Ok ( ( input, false ) )
709+ }
703710}
704711
705712// Try to catch and detect if external command runs to failed.
@@ -1197,14 +1204,72 @@ pub fn eval_subexpression(
11971204 mut input : PipelineData ,
11981205) -> Result < PipelineData , ShellError > {
11991206 for pipeline in block. pipelines . iter ( ) {
1200- for expr in pipeline. elements . iter ( ) {
1201- input = eval_element_with_input ( engine_state, stack, expr, input, true , false ) ?. 0
1207+ for ( expr_indx, expr) in pipeline. elements . iter ( ) . enumerate ( ) {
1208+ if expr_indx != pipeline. elements . len ( ) - 1 {
1209+ input = eval_element_with_input ( engine_state, stack, expr, input, true , false ) ?. 0 ;
1210+ } else {
1211+ // In subexpression, we always need to redirect stdout because the result is substituted to a Value.
1212+ //
1213+ // But we can check if external result is failed to run when it's the last expression
1214+ // in pipeline. e.g: (^false; echo aaa)
1215+ //
1216+ // If external command is failed to run, it can't be convert into value, in this case
1217+ // we throws out `ShellError::ExternalCommand`. And show it's stderr message information.
1218+ // In the case, we need to capture stderr first during eval.
1219+ input = eval_element_with_input ( engine_state, stack, expr, input, true , true ) ?. 0 ;
1220+ if matches ! ( input, PipelineData :: ExternalStream { .. } ) {
1221+ input = check_subexp_substitution ( input) ?;
1222+ }
1223+ }
12021224 }
12031225 }
12041226
12051227 Ok ( input)
12061228}
12071229
1230+ fn check_subexp_substitution ( mut input : PipelineData ) -> Result < PipelineData , ShellError > {
1231+ let consume_result = might_consume_external_result ( input) ;
1232+ input = consume_result. 0 ;
1233+ let failed_to_run = consume_result. 1 ;
1234+ if let PipelineData :: ExternalStream {
1235+ stdout,
1236+ stderr,
1237+ exit_code,
1238+ span,
1239+ metadata,
1240+ trim_end_newline,
1241+ } = input
1242+ {
1243+ let stderr_msg = match stderr {
1244+ None => "" . to_string ( ) ,
1245+ Some ( stderr_stream) => stderr_stream. into_string ( ) . map ( |s| s. item ) ?,
1246+ } ;
1247+ if failed_to_run {
1248+ Err ( ShellError :: ExternalCommand (
1249+ "External command failed" . to_string ( ) ,
1250+ stderr_msg,
1251+ span,
1252+ ) )
1253+ } else {
1254+ // we've captured stderr message, but it's running success.
1255+ // So we need to re-print stderr message out.
1256+ if !stderr_msg. is_empty ( ) {
1257+ eprintln ! ( "{stderr_msg}" ) ;
1258+ }
1259+ Ok ( PipelineData :: ExternalStream {
1260+ stdout,
1261+ stderr : None ,
1262+ exit_code,
1263+ span,
1264+ metadata,
1265+ trim_end_newline,
1266+ } )
1267+ }
1268+ } else {
1269+ Ok ( input)
1270+ }
1271+ }
1272+
12081273pub fn eval_variable (
12091274 engine_state : & EngineState ,
12101275 stack : & Stack ,
0 commit comments