0

I ran

git clone https://git.savannah.gnu.org/git/bash.git
cd bash/
./configure
make
./bash

I noticed that the newly launched Bash instance did not inherit the environment, specifically the PS1 variable that defines the shell prompt, from the parent shell. The inheritance works for /bin/bash

List of sourced files is the same for /bin/bash and ./bash

./bash  -lixc exit 2>&1 | sed -n 's/^+* \(source\|\.\) //p'
/bin/bash  -lixc exit 2>&1 | sed -n 's/^+* \(source\|\.\) //p'

Edit: As aviro mentiond PS1 was defined without export, so when I tried exporting it got inherited, so my initial question was wrong. On my machine PS1 is defined in two files /etc/bash/bashrc

# If not running interactively, don't do anything
[[ $- != *i* ]] && return
[[ $DISPLAY ]] && shopt -s checkwinsize
PS1='[\u@\h \W]\$ '

And /etc/bash/bashrc.d/artix.bashrc

if ${use_color} ; then
    if [[ ${EUID} == 0 ]] ; then
        PS1='\[\033[01;31m\][\h\[\033[01;36m\] \W\[\033[01;31m\]]\$\[\033[00m\] '
    else
        PS1='\[\033[01;36m\][\u@\h\[\033[01;37m\] \W\[\033[01;36m\]]\$\[\033[00m\] '
    fi
else
    if [[ ${EUID} == 0 ]] ; then
        # show root@ when we don't have colors
        PS1='\u@\h \W \$ '
    else
        PS1='\u@\h \w \$ '
    fi
fi

When I ran ./bash the PS1 is \s-\v\$ and I have no idea why.

The command listing all sourced file shows that both of these files should be sourced when run with ./bash, but for some reason they aren't or shell starts in different type/mode. Why?

muru
  • 72,889
  • 1
    PS1 is not an environment variable - it's a shell variable. Those variables are not inherited from the parent. They are read from the profile / bashrc files every time a new shell starts. The question is if you changed the PS1 variable in the parent, or if it comes from one of your profile / bashrc files. – aviro Sep 05 '23 at 14:58
  • 2
    Please [edit] your question and add more details. What value of PS1 do you see, what value do you expect? Do you set the variable in a file like .bashrc? Does the problem not occur if you start /bin/bash instead of ./bash? – Bodo Sep 05 '23 at 15:04
  • @aviro Shell Command Language section states: "Variables shall be initialized from the environment ..." and lists PS1 as one of the Shell Variables. – Vilinkameni Sep 05 '23 at 15:41
  • 1
    @Vilinkameni Yes, If there is an environment variable it would be used instead of the shell variable. So, for instance, if you run export PS1=..., now PS1 will be an environment variable and children bash instances will inherit it. But if you just run PS1=... (without export), it will be shell variable and children bash processes won't inherit it. – aviro Sep 05 '23 at 15:50
  • @aviro So they are "inherited from the parent" - if they are exported in the parent. – Vilinkameni Sep 05 '23 at 15:54
  • @Vilinkameni The point is PS1 is usually (and possibly in the OP's case) not exported. – Kamil Maciorowski Sep 05 '23 at 16:01
  • Merely invoking bash as ./bash or /bin/bash will make it run the commands in bashrc, but not profile because it's not a login shell. – Sotto Voce Sep 05 '23 at 16:09
  • PS1 is especially odd in that Bash explicitly clears it if running non-interactively. If nothing else, that's one reason to set it in bashrc, and it might even be unconditionally set, making it rather hard to inherit the prompt from the environment. But if bashrc doesn't set it, and you run an interactive shell, it will get inherited as usual. That can be useful if you want to run a shell in some unusual environment and feed it a prompt to remind yourself of that. But you need to make sure your startup files support that. – ilkkachu Sep 05 '23 at 16:40
  • If you want to test if the vars get inherited from the environment, run something like PS1=inherited XYZ=inherited ./bash and see what the prompt looks like and what echo "PS1=$PS1" "XYZ=$XYZ" print. Same for the other Bash. – ilkkachu Sep 05 '23 at 16:42
  • @Bodo I said that "The inheritance works for /bin/bash" so the problem doesn't occur, but my initial guess was wrong, it is not related to inheritance. – Rustacean Sep 06 '23 at 17:15
  • that command where you read the output of bash -lix doesn't tell all files it reads. It tells the . or source commands it executes. If you look at the list it outputs, it's missing /etc/profile or .profile, even though Bash does read them for a login shell. And similarly when run without the -l option, the list is missing ~/.bashrc. That is, it doesn't tell the files it runs by itself, meaning it doesn't tell the options it was compiled with. – ilkkachu Sep 06 '23 at 17:37
  • Try running e.g. strings ./bash |grep bashrc and compare with the other binary. Or put something in /etc/bash/bashrc you can use to tell if it was actually read, perhaps something like echo this is /etc/bash/bashrc or whatever. Just be sure to remove it later. – ilkkachu Sep 06 '23 at 17:41

1 Answers1

6

First, you need to understand that PS1 is usually a shell variable, which means it isn't inherited by the children. So unless you explicitly ran export PS1=... and made PS1 an environment variable, every new bash process will get the PS1 (and other shell variables) from the rc files and not from the parent. So you first need to find out where exactly your PS1 is defined.

You can verify that by exporting your PS1:

export PS1

And then run your ./bash. You'll see that in that case, PS1 will be inherited by the new shell.


So why doesn't your compiled bash get the PS1 shell variable you expect from the rc files?

Here's my guess: On many systems, PS1 is being defined in /etc/bash.bashrc. But not all bash versions read this file. It depends on how bash was being compiled. A good rule of thumb would be checking your bash man pages. For instance, for Ubuntu you'll see:

When an interactive shell that is not a login shell is started, bash reads and executes commands from /etc/bash.bashrc and ~/.bashrc, if these files exist. This may be inhibited by using the --norc option. The --rcfile file option will force bash to read and execute commands from file instead of /etc/bash.bashrc and ~/.bashrc.

However, /etc/bash.bashrc is not even mentioned in the bash man page you downloaded from that [git]:

When an interactive shell that is not a login shell is started, bash reads and executes commands from ~/.bashrc, if that file exists. This may be inhibited by using the --norc option. The --rcfile file option will force bash to read and execute commands from file instead of ~/.bashrc.

Additionally, in the README file of bash from Debian, you'll see:

5. What is /etc/bash.bashrc? It doesn't seem to be documented.

The Debian version of bash is compiled with a special option (-DSYS_BASHRC) that makes bash read /etc/bash.bashrc before ~/.bashrc

So in the git repository you've used, you'll see at config-top.h that the line that defines SYS_BASHRC is commented out by default.

/* System-wide .bashrc file for interactive shells. */
/* #define SYS_BASHRC "/etc/bash.bashrc" */

So your bash as it's built by default won't read /etc/bash.bashrc on startup, and if your PS1 is defined there, it won't get it.

If you remove the comment from this line:

#define SYS_BASHRC "/etc/bash.bashrc"

and run make again, my guess is that your new bash will show the PS1 variable you expect.

aviro
  • 5,532
  • 1
    Related: https://unix.stackexchange.com/a/247627/367454 and https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=141193 (example) – Vilinkameni Sep 05 '23 at 16:47
  • Thanks, the only question remaining is why the command listing all sourced files shows that /etc/bash/bashrc is being source when it isn't, I haven't spend much time analyzing this command. – Rustacean Sep 06 '23 at 17:11
  • @Rustacean your command is faulty. It lists explicit source commands, but of course misses the files that bash reads initially, and also files sourced using .. Try something like: PS4=' source:${BASH_SOURCE[0]@Q} ' /bin/bash -lixc exit 2>&1 >/dev/null | grep -Po '^ *source:\S*' | awk '!seen[$0]++' – muru Sep 06 '23 at 22:30
  • The file that sets PS1 is listed by my command, but for some reason it isn't sourced, that's my problem. – Rustacean Sep 10 '23 at 10:20
  • @Rustacean you assume that that's the file that sets your PS1. As repeatedly mentioned, not ALL the files that are being sourced will appear in your list. There might be different files that don't appear in your list. Also, maybe the file you assume doesn't even get to the line you mentioned due to some condition. Based on the command that @muru suggested, please run the following to actually see where your PS1 is defined at: : PS4=' source:${BASH_SOURCE[0]@Q} ' /bin/bash -lixc exit 2>&1 >/dev/null |grep PS1 – aviro Sep 10 '23 at 10:29
  • It seems that @Rustacean is using Artix Linux. In its custom system.bashrc (copied to /etc/bash/bashrc), there is a loop sourcing all files under /etc/bashrc.d in a manner like modprobe and similar tools. (continues) – Vilinkameni Sep 11 '23 at 04:58
  • (continued) The build function contains all the parameters passed to the build process of Bash for Artix Linux. – Vilinkameni Sep 11 '23 at 05:00
  • @Rustacean There is a number of ways you can debug what happens during the startup of your custom-built Bash. Inside all of the relevant files, you can redirect output to some file, print to stderr, or even use logger(1). Not that there may be more custom-set things in a particular package for a particular distro, which you can only know when looking at that packages' source files. – Vilinkameni Sep 11 '23 at 05:09
  • @aviro I've tested by adding simple echo command at the start of the file that sets PS1 and I didn't get any output, so the file isn't sourced at all, I might run that PS4 command later. I would like to remind you that my problem is not about PS1, it's about the list of sourced files and why the list is wrong that's it. – Rustacean Sep 11 '23 at 12:19
  • @Vilinkameni I'm building bash from source, so distro I'm using doesn't really matter, because I haven't use build function you provided, I'll eventually use that build function when I'm done modifying bash code. – Rustacean Sep 11 '23 at 12:20
  • Part of the functionality expected from Bash (specifically, related to PS1) in your distro comes from the scripts provided by maintainers, so it does matter. If you configure Bash in a different manner than the one specified in PKGBUILD, it might not work as expected. – Vilinkameni Sep 11 '23 at 12:25
  • Just one example: -DNON_INTERACTIVE_LOGIN_SHELLS; from the file NEWS in the main source directory: "v. If NON_INTERACTIVE_LOGIN_SHELLS is defined, all login shells read the startup files, even if they are not interactive." – Vilinkameni Sep 11 '23 at 12:35
  • 1
    @Rustacean the command with PS4 will help you find where PS1 is defined. Check the meaning of PS4 in the man pages of bash, and you'll understand how it might help. – aviro Sep 11 '23 at 12:53