Difference between .bashrc and .bash_profile

453

420

What's the difference between .bashrc and .bash_profile and which one should I use?

cfischer

Posted 2010-09-02T14:40:34.913

Reputation: 7 733

If you want a more complete explanation that also involves .profile, have a look at this question: http://superuser.com/questions/789448/choosing-between-bashrc-profile-bash-profile-etc/789705#789705

– Flimm – 2016-07-13T08:53:00.347

This answer also cover some aspects https://stackoverflow.com/questions/415403/whats-the-difference-between-bashrc-bash-profile-and-environment

– Sergey Voronezhskiy – 2017-09-18T08:09:37.003

2

See also this similar question at http://ubuntu.stackexchange.com/questions/1528/bashrc-or-bash-profile/

– Stefan Lasiewski – 2010-09-07T18:38:30.097

Answers

528

Traditionally, when you log into a Unix system, the system would start one program for you. That program is a shell, i.e., a program designed to start other programs. It's a command line shell: you start another program by typing its name. The default shell, a Bourne shell, reads commands from ~/.profile when it is invoked as the login shell.

Bash is a Bourne-like shell. It reads commands from ~/.bash_profile when it is invoked as the login shell, and if that file doesn't exist¹, it tries reading ~/.profile instead.

You can invoke a shell directly at any time, for example by launching a terminal emulator inside a GUI environment. If the shell is not a login shell, it doesn't read ~/.profile. When you start bash as an interactive shell (i.e., not to run a script), it reads ~/.bashrc (except when invoked as a login shell, then it only reads ~/.bash_profile or ~/.profile.

Therefore:

  • ~/.profile is the place to put stuff that applies to your whole session, such as programs that you want to start when you log in (but not graphical programs, they go into a different file), and environment variable definitions.

  • ~/.bashrc is the place to put stuff that applies only to bash itself, such as alias and function definitions, shell options, and prompt settings. (You could also put key bindings there, but for bash they normally go into ~/.inputrc.)

  • ~/.bash_profile can be used instead of ~/.profile, but it is read by bash only, not by any other shell. (This is mostly a concern if you want your initialization files to work on multiple machines and your login shell isn't bash on all of them.) This is a logical place to include ~/.bashrc if the shell is interactive. I recommend the following contents in ~/.bash_profile:

    if [ -r ~/.profile ]; then . ~/.profile; fi
    case "$-" in *i*) if [ -r ~/.bashrc ]; then . ~/.bashrc; fi;; esac
    

On modern unices, there's an added complication related to ~/.profile. If you log in in a graphical environment (that is, if the program where you type your password is running in graphics mode), you don't automatically get a login shell that reads ~/.profile. Depending on the graphical login program, on the window manager or desktop environment you run afterwards, and on how your distribution configured these programs, your ~/.profile may or may not be read. If it's not, there's usually another place where you can define environment variables and programs to launch when you log in, but there is unfortunately no standard location.

Note that you may see here and there recommendations to either put environment variable definitions in ~/.bashrc or always launch login shells in terminals. Both are bad ideas. The most common problem with either of these ideas is that your environment variables will only be set in programs launched via the terminal, not in programs started directly with an icon or menu or keyboard shortcut.

¹ For completeness, by request: if .bash_profile doesn't exist, bash also tries .bash_login before falling back to .profile. Feel free to forget it exists.

Gilles 'SO- stop being evil'

Posted 2010-09-02T14:40:34.913

Reputation: 58 319

Just spent the last hour figuring out how it works in Cygwin. Cygwin, like Terminal, gives you a new login shell for each window. – Sean McSomething – 2016-12-09T21:35:21.497

Just for clarification, "If the shell is not a login shell, it doesn't read ~/.profile" -> Does ~/.profile in this sentence also include ~/.bash_profile? – Abdul – 2017-03-24T11:32:14.453

@Abdul Yes, see the second paragraph of my answer. – Gilles 'SO- stop being evil' – 2017-03-25T00:04:57.880

@Tim I have already answered this many times on [unix.se]. Please learn to search. – Gilles 'SO- stop being evil' – 2018-03-21T21:29:41.817

"The most common problem with either of these ideas..." But that sounds like a problem in general (as you say, there is no standard location for graphical environments to read environment variables from). Even if the graphical environment documents a location, will that location be read when logging in via, say, ssh? It seems to me that there are problems with every approach, so people need to pick their poison. – jamesdlin – 2018-06-07T22:56:52.190

re: Bash is a Bourne-like shell. Speaking as one who was using sh before there was a bash, it was originally referred to as the Bourne again shell. – Jesse Chisholm – 2019-02-21T20:23:53.703

11+1 for good post. ALSO thank you for adding section about "login graphical vs login shell"... I had the problem where I thought ~/.profile would ALWAYS execute for graphical/shell... but it doesn't execute for when the user logs in via graphical login. Thank you for solving that mystery. – Trevor Boyd Smith – 2011-09-17T21:41:46.200

4@Gilles: Could you explain in more detail, with examples, of why running a login shell in every terminal is a bad idea? Is this only an issue with desktop Linux? (I gather that on OS X Terminal runs a login shell every time, and I've never noticed any side effects (though I usually use iTerm). But then I can't think of many environment variables I'd care about outside of a terminal. (Maybe HTTP_PROXY?)) – iconoclast – 2012-06-12T16:38:26.250

2@Brandon If you run a login shell in every terminal, that will override environment variables provided by the environment. In everyday situations, you can get away with it, but it'll come and bite you sooner or later, when you want to set up different variables in a terminal (say, to try out a different version of a program): running a login shell would override your local settings. – Gilles 'SO- stop being evil' – 2012-06-12T17:57:54.813

4The statement ~/.bash_profile can be used instead of ~/.profile, but you also need to include ~/.bashrc if the shell is interactive. is misleading as these are orthogonal issues. No matter if you use ~/.bash_profile or ~/.profile you have to include ~/.bashrc in the one you use if you want settings from there to have effect in the login shell. – Piotr Dobrogost – 2013-06-15T11:20:27.050

@PiotrDobrogost .bash_profile is only read by bash. If you don't have that file, then bash reads .profile instead. If you have only a .profile, then it must include .bashrc, but only if the shell is interactive and is bash, not if the login shell is some other shell. – Gilles 'SO- stop being evil' – 2013-06-15T11:20:31.273

3@Gilles Sure, but the way the sentence is formulated in the answer suggests that the need to include ~/.bashrc has something to do with choosing ~/.bash_profile instead of ~/.profile which is not true. If someone includes ~/.bashrc in any kind of script being sourced at login time (here it's either ~/.bash_profile or ~/.profile) is because he wants settings from ~/.bashrc to be applied to the login shell the same way they are being applied to non-login shell. – Piotr Dobrogost – 2013-06-15T12:29:51.927

1It is a simple task to change the OSX Terminal to be an interactive NON-login shell like some other UNIX distributions. Simply edit the OSX Terminal preferences and change the Shells open with: to the command /usr/bin/login -f -l userid bash -i. This will change the convention to kick off all Terminal as interactive NON-login shells. Keep in mind, that if this is done, the $HOME/.profile will stop being sourced for one. A major overhaul of startup sequence calls would ensue. – Billy McCloskey – 2014-01-19T00:30:23.913

Would you please update your answer with information on .bash_login? This could also be a chance to take into account my previous comments if you wish. – Piotr Dobrogost – 2014-03-06T09:56:45.170

1@PiotrDobrogost Ok, but .bash_login is just an alternate name for .bash_profile that hardly anybody uses. – Gilles 'SO- stop being evil' – 2014-03-06T10:07:53.333

54

From this short article

According to the bash man page, .bash_profile is executed for login shells, while .bashrc is executed for interactive non-login shells.

What is a login or non-login shell?

When you login (eg: type username and password) via console, either physically sitting at the machine when booting, or remotely via ssh: .bash_profile is executed to configure things before the initial command prompt.

But, if you've already logged into your machine and open a new terminal window (xterm) inside Gnome or KDE, then .bashrc is executed before the window command prompt. .bashrc is also run when you start a new bash instance by typing /bin/bash in a terminal.

Jarvin

Posted 2010-09-02T14:40:34.913

Reputation: 6 712

12Slight updates:

'Executed' is probably a slightly misleading term, they're both sourced. Executed sounds like it's run as a script, fork/exec yadda yadda. It's run in the context of the current shell

More importantly, .bashrc is run much more often. It is run on every bash script run, and also if you don't have a .bash_profile.

Also, depending how you set up your xterms, you may create a shell that sources .bash_profile – Rich Homolka – 2010-09-02T17:57:07.833

35

Back in the old days, when pseudo tty's weren't pseudo and actually, well, typed, and UNIXes were accessed by modems so slow you could see each letter being printed to your screen, efficiency was paramount. To help efficiency somewhat you had a concept of a main login window and whatever other windows you used to actually work. In your main window, you'd like notifications to any new mail, possibly run some other programs in the background.

To support this, shells sourced a file .profile specifically on 'login shells'. This would do the special, once a session setup. Bash extended this somewhat to look at .bash_profile first before .profile, this way you could put bash only things in there (so they don't screw up Bourne shell, etc, that also looked at .profile). Other shells, non-login, would just source the rc file, .bashrc (or .kshrc, etc).

This is a bit of an anachronism now. You don't log into a main shell as much as you log into a gui window manager. There is no main window any different than any other window.

My suggestion - don't worry about this difference, it's based on an older style of using unix. Eliminate the difference in your files. The entire contents of .bash_profile should be:

[ -f $HOME/.bashrc ] && . $HOME/.bashrc

And put everything you actually want to set in .bashrc

Remember that .bashrc is sourced for all shells, interactive and non-interactive. You can short circuit the sourcing for non-interactive shells by putting this code near the top of .bashrc:

[[ $- != *i* ]] && return

Rich Homolka

Posted 2010-09-02T14:40:34.913

Reputation: 27 121

6

This is a bad idea, see my answer. In particular, your environment variables will only be set in programs launched via the terminal, not in programs started directly with an icon or menu or keyboard shortcut.

– Gilles 'SO- stop being evil' – 2010-09-02T19:24:35.200

4@Gilles I don't understand why you claim this. With .$HOME/.bashrc as Rich showed above, settings in .bashrc will be available in login shells, and thus the desktop environment as well. For example, on my Fedora system, gnome-session is started as -$SHELL -c gnome-session, so .profile is read. – Mikel – 2012-06-02T16:25:38.623

2@PiotrDobrogost Oh, yes, there's another problem with Rich's answer. Including .bashrc in .profile typically doesn't work, because .profile may be executed by /bin/sh and not bash (e.g. on Ubuntu for a graphical login by default), and that shell may not be interactive (e.g. for a graphical login). – Gilles 'SO- stop being evil' – 2013-06-15T11:24:50.280

3@Gilles re: "including .bashrc in .profile" is not at all what was recommended (quite the contrary, in fact). Either the answer was edited (it doesn't appear so), or your comments don't align with what is being said. – michael – 2013-07-29T06:17:39.607

2In general, +1, but I would add to the recommendation to "short circuit...for non-interactive shells" ("near the top of .bashrc: [[ $- != *i* ]] && return"); I do like some of my .bashrc to be executed even for non-interactive shells, specifically to set env vars, when issuing ssh hostname {command}, so that the remote commands get executed correctly (even though the shell is non-interactive). But other settings later in .bashrc should be ignored. I usually check for TERM=dumb and/or unset, and then bail out early. – michael – 2013-07-29T06:30:04.283

19

Have a look at this excellent blog post by ShreevatsaR. Here's an extract, but go to the blog post, it includes an explanation for terms like "login shell", a flow chart, and a similar table for Zsh.

For Bash, they work as follows. Read down the appropriate column. Executes A, then B, then C, etc. The B1, B2, B3 means it executes only the first of those files found.

+----------------+-----------+-----------+------+
|                |Interactive|Interactive|Script|
|                |login      |non-login  |      |
+----------------+-----------+-----------+------+
|/etc/profile    |   A       |           |      |
+----------------+-----------+-----------+------+
|/etc/bash.bashrc|           |    A      |      |
+----------------+-----------+-----------+------+
|~/.bashrc       |           |    B      |      |
+----------------+-----------+-----------+------+
|~/.bash_profile |   B1      |           |      |
+----------------+-----------+-----------+------+
|~/.bash_login   |   B2      |           |      |
+----------------+-----------+-----------+------+
|~/.profile      |   B3      |           |      |
+----------------+-----------+-----------+------+
|BASH_ENV        |           |           |  A   |
+----------------+-----------+-----------+------+
|                |           |           |      |
+----------------+-----------+-----------+------+
|                |           |           |      |
+----------------+-----------+-----------+------+
|~/.bash_logout  |    C      |           |      |
+----------------+-----------+-----------+------+

Flimm

Posted 2010-09-02T14:40:34.913

Reputation: 6 317

Rather than posting the same answer on multiple questions it is preferred if you can tailor your answer to the specific needs of the asker. If the answer is exactly the same for both questions then you should be posting a single answer and voting to close the other questions as duplicates of the original. – Mokubai – 2016-07-13T18:13:19.143

1@Mokubai The other question has already been marked as a duplicate of this one. – Flimm – 2016-07-13T20:34:19.517

@ElipticalView: by set to do nothing, you're referring to the line: [ -z "$PS1" ] && return? The table in my answer is giving the list of scripts run by Bash regardless of the contents of the scripts, if the script itself has the line [ -z "$PS1" ] && return, of course that would take effect, but I don't think that should mean I should change the table. – Flimm – 2016-10-18T10:51:54.200

5

A BETTER COMMENT FOR THE HEAD OF /ETC/PROFILE

Building on Flimm's great answer above, I insered this new comment at the head of my Debian /etc/profile, (you might need to adjust it for your distro.):

# For BASH: Read down the appropriate column. Executes A, then B, then C, etc.
# The B1, B2, B3 means it executes only the first of those files found.  (A)
# or (B2) means it is normally sourced by (read by and included in) the
# primary file, in this case A or B2.
#
# +---------------------------------+-------+-----+------------+
# |                                 | Interactive | non-Inter. |
# +---------------------------------+-------+-----+------------+
# |                                 | login |    non-login     |
# +---------------------------------+-------+-----+------------+
# |                                 |       |     |            |
# |   ALL USERS:                    |       |     |            |
# +---------------------------------+-------+-----+------------+
# |BASH_ENV                         |       |     |     A      | not interactive or login
# |                                 |       |     |            |
# +---------------------------------+-------+-----+------------+
# |/etc/profile                     |   A   |     |            | set PATH & PS1, & call following:
# +---------------------------------+-------+-----+------------+
# |/etc/bash.bashrc                 |  (A)  |  A  |            | Better PS1 + command-not-found 
# +---------------------------------+-------+-----+------------+
# |/etc/profile.d/bash_completion.sh|  (A)  |     |            |
# +---------------------------------+-------+-----+------------+
# |/etc/profile.d/vte-2.91.sh       |  (A)  |     |            | Virt. Terminal Emulator
# |/etc/profile.d/vte.sh            |  (A)  |     |            |
# +---------------------------------+-------+-----+------------+
# |                                 |       |     |            |
# |   A SPECIFIC USER:              |       |     |            |
# +---------------------------------+-------+-----+------------+
# |~/.bash_profile    (bash only)   |   B1  |     |            | (doesn't currently exist) 
# +---------------------------------+-------+-----+------------+
# |~/.bash_login      (bash only)   |   B2  |     |            | (didn't exist) **
# +---------------------------------+-------+-----+------------+
# |~/.profile         (all shells)  |   B3  |     |            | (doesn't currently exist)
# +---------------------------------+-------+-----+------------+
# |~/.bashrc          (bash only)   |  (B2) |  B  |            | colorizes bash: su=red, other_users=green
# +---------------------------------+-------+-----+------------+
# |                                 |       |     |            |
# +---------------------------------+-------+-----+------------+
# |~/.bash_logout                   |    C  |     |            |
# +---------------------------------+-------+-----+------------+
#
# ** (sources !/.bashrc to colorize login, for when booting into non-gui)

And this note at the head of each of the other setup files to refer to it:

# TIP: SEE TABLE in /etc/profile of BASH SETUP FILES AND THEIR LOAD SEQUENCE

Worth noting I think is that Debian's /etc/profile by default sources (includes) /etc/bash.bashrc (that's when /etc/bash.bashrc exists). So login scripts read both /etc files, while non-login reads only bash.bashrc.

Also of note is that /etc/bash.bashrc is set to do nothing when it's not run interactively. So these two files are only for interactive scripts.

Elliptical view

Posted 2010-09-02T14:40:34.913

Reputation: 864

4

The configuration logic of bash's itself is not crazy complicated and explained in other answers in this page, on serverfault and in many blogs. The problem however is what the Linux distributions make of bash, I mean the complex and various ways they configure bash by default. http://mywiki.wooledge.org/DotFiles mentions some of these quirks briefly. Here's one sample trace on Fedora 29, it shows which files source which other file(s) and in which order for a very simple scenario: remotely connecting with ssh and then starting another subshell:

ssh fedora29
 └─ -bash # login shell
      ├── /etc/profile
      |    ├─ /etc/profile.d/*.sh
      |    ├─ /etc/profile.d/sh.local
      |    └─ /etc/bashrc
      ├── ~/.bash_profile
      |    └─ ~/.bashrc
      |          └─ /etc/bashrc
      |
      |
      └─ $ bash  # non-login shell
            └─ ~/.bashrc
                 └─ /etc/bashrc
                       └─ /etc/profile.d/*.sh

Fedora's most complex logic is in /etc/bashrc. As seen above /etc/bashrc is a file bash itself doesn't know about, I mean not directly. Fedora's /etc/bashrc tests whether:

  • it's being sourced by a login shell,
  • it's being sourced by an interactive shell,
  • it has already been sourced

... and then does completely different things depending on those.

If you think can remember the graph above then too bad because it's not nearly enough: this graph merely describes just one scenario, slightly different things happen when running non-interactive scripts or starting a graphical session. I've omitted ~/.profile. I've omitted bash_completion scripts. For backward compatibility reasons, invoking bash as /bin/sh instead of /bin/bash changes its behaviour. What about zsh and other shells? And of course different Linux distributions do things differently, for instance Debian and Ubuntu come with a non-standard version of bash, it has Debian-specific customization(s). It notably looks for an unusual file: /etc/bash.bashrc. Even if you stick to a single Linux distribution it probably evolves over time. Wait: we haven't even touched macOS, FreeBSD,... Finally, let's have a thought for users stuck with the even more creative ways their admins have configured the system they have to use.

As the never-ending stream of discussions on this topic demonstrates, it's a lost cause. As long as you just want to add new values, some "trial and error" tends to be enough. The real fun begins when you want to modify in one (user) file something already defined in another (in /etc). Then be prepared to spend some time engineering a solution that will never be portable.

For a last bit of fun here's the "source graph" for the same, simple scenario on Clear Linux as of June 2019:

ssh clearlinux
 └─ -bash # login shell
      ├── /usr/share/defaults/etc/profile
      |    ├─ /usr/share/defaults/etc/profile.d/*
      |    ├─ /etc/profile.d/*
      |    └─ /etc/profile
      ├── ~/.bash_profile
      |
      |
      └─  $ bash   # non-login shell
           ├─ /usr/share/defaults/etc/bash.bashrc
           |      ├─ /usr/share/defaults/etc/profile
           |      |    ├─ /usr/share/defaults/etc/profile.d/*
           |      |    ├─ /etc/profile.d/*
           |      |    └─ /etc/profile
           |      └─ /etc/profile
           └─ ~/.bashrc

MarcH

Posted 2010-09-02T14:40:34.913

Reputation: 173