This same problem happens for SUBSHELL_PAREN, SUBSHELL_COMSUB,
SUBSHELL_PIPE and SUBSHELL_COPROC as well as SUBSHELL_ASYNC

Test case (This must be sourced to see SHLVL == 1 which causes
/etc/bash.bashrc to be sourced in a shell started by ssh)

$ cat test.sh
test1="bash -c 'echo \$SHLVL'"
test2="{ bash -c 'echo \$SHLVL' ; }"

do_test()
{
echo "****** Testing $1 $2"
eval $2
wait
echo "***** DONE *****"
echo
}

do_coproctest()
{
echo "****** Testing COPROC $1"
eval coproc $1
IFS= read -ru ${COPROC[0]} x; printf '%s\n' "$x"
wait
echo "***** DONE *****"
echo
}


do_test BASIC "$test1"
do_test BASIC "$test2"

#ASYNC
do_test ASYNC "$test1 &"
do_test ASYNC "$test2 &"

#PAREN
do_test PAREN "( $test1 )"
do_test PAREN "( $test2 )"

#COMSUB
do_test COMSUB "echo \$( $test1 )"
do_test COMSUB "echo \$( $test2 )"

#PIPE
do_test PIPE "$test1 | cat"
do_test PIPE "$test2 | cat"

#PROCSUB
do_test PROCSUB "cat <( $test1 )"
do_test PROCSUB "cat <( $test2 )"

#COPROC
do_coproctest "$test1"
do_coproctest "$test2"

##############

Proposed patch:
diff -urN bash-5.1.orig/execute_cmd.c bash-5.1/execute_cmd.c
--- bash-5.1.orig/execute_cmd.c 2020-10-12 14:16:13.000000000 +0000
+++ bash-5.1/execute_cmd.c      2020-10-12 14:16:13.000000000 +0000
@@ -5487,7 +5487,12 @@
#if 0 /* TAG: bash-5.2 psmith 10/11/2020 */
if (nofork && pipe_in == NO_PIPE && pipe_out == NO_PIPE && (subshell_environment & SUBSHELL_PIPE) == 0)
#else
-      if (nofork && pipe_in == NO_PIPE && pipe_out == NO_PIPE)
+      if (nofork && pipe_in == NO_PIPE && pipe_out == NO_PIPE &&
+         (subshell_environment & SUBSHELL_ASYNC) == 0 &&
+         (subshell_environment & SUBSHELL_PAREN) == 0 &&
+         (subshell_environment & SUBSHELL_COMSUB) == 0 &&
+         (subshell_environment & SUBSHELL_PIPE) == 0 &&
+         (subshell_environment & SUBSHELL_COPROC) == 0)
#endif
      adjust_shell_level (-1);

#############

It seems absurd that:
bash -c 'echo $SHLVL'
{ bash -c 'echo $SHLVL' ; }

should both have SHLVL == 2 but if they are executed async then the
first one runs with SHLVL == 1 but not the second.

The proposed patch causes them all to run at SHLVL == 2 which then
avoids the issue of SHLVL == 1 causing /etc/bash.bashrc to be sourced
when running under ssh.

It also fixes issues with make running in interactive shells
unexpectedly.

Without the fix:
$ cat Makefile.test
all:
      echo $$SHLVL
$ make -f Makefile.test
echo $SHLVL
1
$ make -f Makefile.test | cat
echo $SHLVL
0
$


This does not change the behaviour reported in #702559


#################

N.B. The sourcing of /etc/bash.bashrc is most easily seen by:

$ ( bash -uc : )
/etc/bash.bashrc: line 8: PS1: unbound variable
$

This issue of unbound variables in bash.bashrc was reported in #941248

###################
Results of running test.sh in bullseye:
(If it is sourced the results are, as expected, one lower)

# ./test.sh
****** Testing BASIC bash -c 'echo $SHLVL'
3
***** DONE *****

****** Testing BASIC { bash -c 'echo $SHLVL' ; }
3
***** DONE *****

****** Testing ASYNC bash -c 'echo $SHLVL' &
2
***** DONE *****

****** Testing ASYNC { bash -c 'echo $SHLVL' ; } &
3
***** DONE *****

****** Testing PAREN ( bash -c 'echo $SHLVL' )
2
***** DONE *****

****** Testing PAREN ( { bash -c 'echo $SHLVL' ; } )
3
***** DONE *****

****** Testing COMSUB echo $( bash -c 'echo $SHLVL' )
2
***** DONE *****

****** Testing COMSUB echo $( { bash -c 'echo $SHLVL' ; } )
3
***** DONE *****

****** Testing PIPE bash -c 'echo $SHLVL' | cat
2
***** DONE *****

****** Testing PIPE { bash -c 'echo $SHLVL' ; } | cat
3
***** DONE *****

****** Testing PROCSUB cat <( bash -c 'echo $SHLVL' )
3
***** DONE *****

****** Testing PROCSUB cat <( { bash -c 'echo $SHLVL' ; } )
3
***** DONE *****

****** Testing COPROC bash -c 'echo $SHLVL'
2
***** DONE *****

****** Testing COPROC { bash -c 'echo $SHLVL' ; }
3
***** DONE *****

##################
with the proposed patch applied:

****** Testing BASIC bash -c 'echo $SHLVL'
3
***** DONE *****

****** Testing BASIC { bash -c 'echo $SHLVL' ; }
3
***** DONE *****

****** Testing ASYNC bash -c 'echo $SHLVL' &
3
***** DONE *****

****** Testing ASYNC { bash -c 'echo $SHLVL' ; } &
3
***** DONE *****

****** Testing PAREN ( bash -c 'echo $SHLVL' )
3
***** DONE *****

****** Testing PAREN ( { bash -c 'echo $SHLVL' ; } )
3
***** DONE *****

****** Testing COMSUB echo $( bash -c 'echo $SHLVL' )
3
***** DONE *****

****** Testing COMSUB echo $( { bash -c 'echo $SHLVL' ; } )
3
***** DONE *****

****** Testing PIPE bash -c 'echo $SHLVL' | cat
3
***** DONE *****

****** Testing PIPE { bash -c 'echo $SHLVL' ; } | cat
3
***** DONE *****

****** Testing PROCSUB cat <( bash -c 'echo $SHLVL' )
3
***** DONE *****

****** Testing PROCSUB cat <( { bash -c 'echo $SHLVL' ; } )
3
***** DONE *****

****** Testing COPROC bash -c 'echo $SHLVL'
3
***** DONE *****

****** Testing COPROC { bash -c 'echo $SHLVL' ; }
3
***** DONE *****

Reply via email to