[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/