Customized prompt does not hold when a child bash is ran

I have been learning bash, and while doing so I played around with the .bash_profile file to be able to put greeting messages etc. Later I just removed these changes. But after doing that my default configuration of prompt got lost: originally, the prompt was all in bold, and \w part was blue so that when I was in a deeply nested directory the prompt would not seem so entangled. I think that was the default for Ubuntu (correct me if i'm wrong), however like I said it got lost and my prompt was non-bold and monochromatic resulting in a mess when I'm in long named directories.

So, last night I tried customizing my prompt in the fashion I mentioned above. It worked well after I added the code to .bash_profile

Code was like this:

export PS1="\[$(tput bold)\]\u@\h:\[$(tput sgr 0)\]\e[1;34m\w$ \e[m"

However if I try to run another bash shell in the current one, the prompt becomes unformatted:

Is that normal? Isn't the whole point of exporting a variable to make it accessible from all the child processes forked from that shell? Why it doesn't that apply to this situation?


Solution 1:

.bash_profile is sourced by login shells only. It has been sourced when you logged into the X-session, and the environment inherited as @Serg explains in detail. Somehow you have managed a configuration in which this environment is not overridden by .bashrc, perhaps setting your terminal to open a login shell by default. I can reproduce the behaviour you experienced by configuring my terminal like this:

this causes the shell to open as a login shell, but any child called will be a non-login shell, and source .bashrc, not .bash_profile unless, as @Serg suggests, the -l flag is used.

TL;DR
If you want the custom prompt to be sourced by interactive shells, put the code in your .bashrc

Solution 2:

TL;DR: just put the call to PS1 into ~/.bashrc or call subshells with -l flag

Zanna's answer appropriately suggests to set PS1 in ~/.bashrc to be sourced by interactive shells.

You can, however , use -l flag to treat subshell as login shell:

DIR:/xieerqi|04:25|skolodya@ubuntu:
$ echo "PS1='TEST$ '" > ~/.profile

DIR:/xieerqi|04:25|skolodya@ubuntu:
$ bash
xieerqi@eagle:~$ exit

DIR:/xieerqi|04:25|skolodya@ubuntu:
$ bash -l
TEST$ 

The "Why"

Is that normal? Isn't the whole point of exporting a variable to make it accessible from all the child processes forked from that shell? Why it doesn't apply to this stiuation?

Yes, that's the expected behavior. When you export something, variables should propagate downwards to subshells.

xieerqi@eagle:~$ export VAR=303
xieerqi@eagle:~$ bash
xieerqi@eagle:~$ echo $VAR
303
xieerqi@eagle:~$ ksh
$ echo $VAR
303

The issue again is ~/.bashrc . The default ~/.bashrc file has lines which override PS1. So, your variable was exported , but then uset once interactive shell sourced ~/.bashrc . The example of this situation has been observed by Gilles' answer on one of the questions at Unix Stackexchange.

As for ~/.profile it is actually encouraged to set and export environment variables from there and is a frequent practice.

To address Zanna's comment as to why the very first shell did get colorized, I believe this is the cause:

When bash is invoked as an interactive login shell . . . it first reads and executes commands from the file /etc/profile, if that file exists. After reading that file, it looks for ~/.bash_profile, ~/.bash_login, and ~/.profile, in that order, and reads and executes commands from the first one that exists and is readable. (from bash man page, emphasis added)

What happened is that once you login, bash finds ~/.bash_profile and sources it as the first file found. The other shells are interactive non-login shells, so only ~/.bashrc is sourced after that.