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 *****