44

I'm having trouble wrapping my head around what belongs in ~/.profile and what belongs in ~/.bashrc.

From what I've read, it seems to me that ~/.profile should be used for environment variables and ~/.bashrc for aliases, functions, and the like. If I move all my export statements from ~/.bashrc to ~/.profile, would everything work as it should, or am I about to break something?

(Here's my dotfiles repo if you want to look over both files.)

EDIT 2022-06-03: I've moved most of my environment variables from ~/.bashrc to ~/.profile and have assured myself that ~/.bash_profile sources ~/.profile. The only environment variables I've left in ~/.bashrc are those that only matter when I'm working in a shell, e.g., those pertaining to less, the prompts, slrn, and the like. Everything seems to be working well. Thanks for the help.

3
  • Does this answer your question? Why is /etc/profile not invoked for non-login shells? Commented Jun 2, 2022 at 15:18
  • 1
    @ArturMeinild It didn't, no. I'm clear on the "login" versus "non-login" thing. As things stand in my setup, I'm pretty sure the difference isn't important. I'm only considering moving all my environment variables (except for the prompt) to my ~/.profile.
    – MDeBusk
    Commented Jun 2, 2022 at 22:54
  • 1
    Problem I have here is when I open a terminal . profile is sourced again doubling my path. Argh.
    – RichieHH
    Commented Nov 22, 2023 at 10:42

3 Answers 3

46

It helps to understand which files get sourced, when, and why.

  • .profile is sourced by a login shell on startup. Typically, the only login shell you start is the one started when you log in, but you can run a login shell at any time with bash -l. (Also, on macOS, there is no initial login shell, so terminal emulators tend to run a login shell for each new window.)

  • .profile is an ideal place to set environment variables that can be inherited by any program started from the login shell.

  • .bashrc, on the other hand, is sourced by non-login interactive shells, such as those started by terminal windows (most configs also source .bashrc in interactive login shells though). This is where you set things specific to your interactive shell that aren't otherwise inherited from the parent process. For example, PS1 is set here because only interactive shells care about its value, and any interactive shell will source .bashrc anyway, so there is no need to define and export PS1 from .profile.

  • And though you didn't ask, it's worth pointing out the difference between .profile and .bash_profile here. .profile is "shared" by all POSIX shells (such as dash), so don't put anything bash-specific here. .bash_profile, though, is only used by bash, so you can use bash extensions in it. If .bash_profile is present, .profile will be ignored, so if for whatever reason you want to use both, you can add . ~/.profile to the top of your .bash_profile.

10
  • This is helpful. Thank you. And I do appreciate the last paragraph. I don't think I have anything bash-specific regarding environment variables, and I do have both ~/.profile and .~/.bash_profile Looks like I have some more poking around to do.
    – MDeBusk
    Commented Jun 2, 2022 at 14:52
  • 1
    Mostly, it just means avoiding using things like [[ ... ]] in .profile.
    – chepner
    Commented Jun 2, 2022 at 15:33
  • No, it's not run for every command you issue in a terminal. It's sourced by bash when it is started as an interactive shell (i.e., when its standard input is a terminal or the -i option is explicitly used).
    – chepner
    Commented Jun 2, 2022 at 15:58
  • 1
    @MDeBusk If you look at the top of the ~/.profile file, you will see that ~/.profile is not called by bash if you have a ~/.bash_profile.
    – Terrance
    Commented Jun 2, 2022 at 16:05
  • @ubfan1 That's .bashrc being sourced by bash, not ls.
    – chepner
    Commented Jun 2, 2022 at 16:06
19

~/.profile is only called when you first log into your account. Any changes you make after that it would be wise to log out and back in so settings take effect. ~/.bashrc is called every time you launch a terminal window. There is another profile file and it is in the /etc/ directory. The main difference between the two is that the /etc/profile is called when anyone logs into the system, and the ~/.profile is called when only the user logs in.

If your export lines are only used in a terminal session then I would add them to the ~/.bashrc file as they are only valid during the terminal (bash) session. But, if you want them to be there with or without a terminal open, add them to the ~/.profile file, but like @chepner has stated do not put bash specific commands in the ~/.profile file.

If you screw up these files, there are default files stored in the /etc/skel/ directory that you can copy back over to your home directory. Also, the /etc/skel/ files are also used when you boot to a LiveUSB/CD/DVD, so if you modify those on your live media and then when it completes the boot you can have your own variables set.

16
  • this doesn't seem to the question about setting exported variables in .profile vs. in .bashrc?
    – ilkkachu
    Commented Jun 2, 2022 at 12:00
  • @ilkkachu I don't understand what you are asking here. Please elaborate. And also, this really is a question that is based more on opinion since it is a preference thing.
    – Terrance
    Commented Jun 2, 2022 at 12:43
  • 1
    Assuming that your terminal sessions are all started from your login shell (or a descendent thereof), they will inherit any environment variables defined in .profile. The key is to understand that it's not terminal windows, per se, that use .bashrc, but the interactive non-login shells that they typically run by default.
    – chepner
    Commented Jun 2, 2022 at 13:32
  • 2
    Original answer was actually better, being less technical and answering the question, i.e., what to put in .profile and what in .bashrc, more directly.
    – vanadium
    Commented Jun 2, 2022 at 15:52
  • 1
    Upvoted. It is now to the OP to choose ;)
    – vanadium
    Commented Jun 2, 2022 at 18:12
13

chepner's answer covers the overall principles. There are a few other subtleties that you want to take note of.

First, login shells do not source .bashrc even if they are interactive. Thus, you probably want a .bash_profile that contains code like the following:

interactive() { [[ $- = *i* ]]; }
interactive && . $HOME/.bashrc || echo 1>&2 "ERROR: .bashrc failed with retval $?"

This won't make much difference on a console login into a graphical environment, but will make quite a difference on a text console or ssh login.

You don't necessarily need to do the interactive test; I actually source .bashrc even for non-interactive shells (though this is arguably not a good idea in some circumstances).

Note that if you use non-Bash shells as well, you'll also need a .profile with whatever environment variables etc. you want for those. Bash will ignore your .profile when you have a .bash_profile, but of course the latter can source the former.


Not every fresh login (i.e., a shell created not by your user id but by a root process that has authenticated you) is considered a "login shell." In particular, giving a command to an ssh invocation (ssh somehost.example.com 'echo $-') will not be a "login shell" and .bash_profile/.bash_login/.profile will not be sourced. Here's a table showing what's considered a "login" or interactive shell and what's executed for various invocations

State Invocation
Login (L) argv[0][0] == '-', --login
Interactive (I) -i, stdin is tty
Remote (R) stdin is "network connection" (see below)
  • '•' = set; blank = not set; '-' = not checked or don't care.
  • inh: Inherits environment from a parent (other than init); i.e., it's not a "fresh login" and the parent may expect that the environment be kept intact.
  • p: sources /etc/profile then first of ~/.bash_profile, ~/.bash_login, ~/.profile
  • rc: sources /etc/bash.bashrc then ~/.bashrc
L I R inh p rc Example
- ssh host.com (sshd sets argv[0]="-bash")
- ssh host.com </dev/null (sshd sets argv[0]="-bash")
bash -i, bash on tty
bash hello.sh, bash -c echo foo,
ssh host.com 'echo $-' (ssh runs bash -c 'echo $-)

The table comes from this document; there's some further information there that might also be useful. (Anybody who feels something there should be in this answer should feel free to edit this and copy it in.)

1
  • 2
    This is interesting. I didn't know this about ssh sessions. Thank you.
    – MDeBusk
    Commented Jun 3, 2022 at 5:42

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .