help-bash
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: So confused: bash vs ssh and SHLVL=0?


From: Chet Ramey
Subject: Re: So confused: bash vs ssh and SHLVL=0?
Date: Sun, 11 Oct 2020 15:05:56 -0400
User-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:68.0) Gecko/20100101 Thunderbird/68.12.0

On 10/10/20 4:43 PM, Paul Smith wrote:
> I'm running bash 5.0.17(1)-release (x86_64-pc-linux-gnu) on Ubuntu
> 20.04 GNU/Linux
> 
> I'm seeing strange behavior with a combination of ssh and bash and
> SHLVL.
> 
> For example if I add an "echo bashrc" into my ~/.bashrc and I do this:
> 
>   me@local$ ssh remote
> 
>   me@remote$ /bin/bash -c 'echo hi'
>   hi
> 
> it is not sourcing ~/.bashrc, as you'd expect, but if I do this:
> 
>   me@local$ ssh remote
> 
>   my@remote$ echo 'all:; echo hi' | make -f- SHELL=/bin/bash
>   echo hi
>   bashrc
>   hi
> 
> it DOES source my ~/.bashrc!!  I've tried this on other remote systems
> running older versions of GNU/Linux and bash and it doesn't behave like
> this.

Neither does bash-5.0 as distributed. After adding a similar echo to my
bashrc (my login shell is /bin/bash5):

jenna-2(1)$ echo $BASH_VERSION
5.0.18(9)-release
jenna-2(1)$ ssh localhost
Password:
Last login: Thu Oct  1 17:00:11 2020
jenna-2(1)$ echo 'all:; echo hi' | make -f- SHELL=/bin/bash5
echo hi
hi
jenna-2(1)$ echo $BASH_VERSION
5.0.18(9)-release


> After a lot of banging my head I discovered some mailing list threads
> that explained that bash tests SHLVL to decide whether to source
> ~/.bashrc if SSH_CLIENT is set.

The SSH_CLIENT part is not standard behavior. There is a build-time option,
disabled by default, that enables this, which is intended to allow the
`bash -c' that is run by ssh to execute a command to source the bashrc.

It obviously will trigger on any other instance of `bash -c', such as the
one `make' invokes. That is the reason I disabled it by default back in
2001.

Your vendor, probably Debian, appears to have enabled it and not documented
the consequences.

> 
> This info would be great to add to the man page, which simply talks
> about "being run with its standard input connected to a network
> connection", which I don't really understand... how can bash know that?

That would have been good for Debian to do.

As for detecting when the standard input is a network connection, that
just means file descriptor 0 is connected to a socket, which you can
discover with getpeername() or stat().


> However, the problem is that if I invoke a NON-shell, SHLVL is
> DECREMENTED and set back to 0 in that process's environment!!
> 
>   $ echo $SHLVL
>   1
> 
>   $ env | grep SHLVL
>   SHLVL=0

Not exactly. If you run `env' without the pipe, SHLVL=1. What happens is
that bash optimizes out the extra fork because of the pipeline, making it
into an implicit `exec'. When it does this, it decrements the shell level
like `exec' does, otherwise a bash run as the child process ends up
incrementing it twice.

Here's part of the discussion of the issue:

https://lists.gnu.org/archive/html/bug-bash/2016-09/msg00000.html

> Can anyone explain how or why bash decides to decrement SHLVL when
> invoking a process?  

Basically, it decrements the shell level before performing the equivalent
of the `exec' builtin. Sometimes it optimizes out a fork to make it
equivalent to an exec. Ordinarily it doesn't matter.

> This is clearly not good for my build environment
> as it causes all my make recipes to have ~/.bashrc sourced, which
> resets critical environment variables etc.

I'd file a bug report with Debian. In the meantime, you can test for an
interactive shell at the beginning of your .bashrc and `return' if it's
not one.

Chet
-- 
``The lyf so short, the craft so long to lerne.'' - Chaucer
                 ``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, UTech, CWRU    chet@case.edu    http://tiswww.cwru.edu/~chet/



reply via email to

[Prev in Thread] Current Thread [Next in Thread]