Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Before we begin, first note that bashrc refers to something that runs in each and every new shell, and profile refers to something that runs only in interactive shells (used by a user at a keyboard, not just a shell script, for example). They aren’t the same and you don’t want them to be the same.

I'm not an expert on bash exactly though I am a heavy shell user (POSIX shell for scripting) but this part doesn't sound right. When is .bashrc ever executed when bash isn't interactive? And as far as I can tell when I open new shells .profile isn't read. I am using Linux and tmux and the reason I mention tmux is that it opens bash as a login shell and therefore .bash_profile is also loaded. Is this a mac OS thing or the version of bash mac OS comes with, which I believe is really old due to some license issues.



Which startup files are read by bash and other shells in which state is very inconsistent, even across distributions of Linux. I've collapsed all of mine into .bashrc and simply source that file from the other possibilities. And on the rare occasion that I care about interactive vs not, I can make that distinction explicitly in the code.


I ran an eBPF program called opensnoop [1] to capture what files were opened during login to a system and then re-launching bash. Looks like both are read during initial login but only .bashrc for non-login shells. Output is below.

  24435  bash                3   0 /etc/profile
  24435  bash                3   0 /etc/profile.d/
  24435  bash                3   0 /etc/profile.d/256term.sh
  24435  bash                3   0 /etc/profile.d/colorgrep.sh
  24435  bash                3   0 /etc/profile.d/colorls.sh
  24435  bash                3   0 /etc/profile.d/lang.sh
  24435  bash                3   0 /etc/profile.d/less.sh
  24435  bash                3   0 /etc/profile.d/which2.sh
  24435  bash                3   0 /etc/profile.d/sh.local
  24435  bash                3   0 /home/centos/.bash_profile
  24435  bash                3   0 /home/centos/.bashrc
  24435  bash                3   0 /etc/bashrc

  24736  bash                3   0 /home/centos/.bashrc
  24736  bash                3   0 /etc/bashrc
  24736  bash                3   0 /etc/profile.d/
  24736  bash                3   0 /etc/profile.d/256term.sh
  24736  bash                3   0 /etc/profile.d/colorgrep.sh
  24736  bash                3   0 /etc/profile.d/colorls.sh
  24736  bash                3   0 /etc/profile.d/lang.sh
  24736  bash                3   0 /etc/profile.d/less.sh
  24736  bash                3   0 /etc/profile.d/which2.sh

[1] http://www.brendangregg.com/blog/2014-07-25/opensnoop-for-li...


Be careful that some of those files explicitly include others. For example my (default) ~/.profile includes ~/.bashrc, my ~/.bash_profile includes ~/.profile, /etc/profile includes /etc/bash.bashrc...

So your capture here doesn't show only the files that bash itself decided to load. You also won't see the fallback files (e.g. bash will open .profile if .bash_profile doesn't exist).


as far as I can tell when I open new shells .profile isn't read

True, iff you have a .bash_profile. Bash only reads the first of ~/.bash_profile, ~/.bash_login, ~/.profile. It will ignore the rest of the list once it's found an existing file.


Still, they're not read with every new interactive shell. They're read only with login shells. From the manual:

> When bash is invoked as an interactive login shell, or as a non-interactive shell with the --login option, 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,

> When an interactive shell that is not a login shell is started, bash reads and executes commands from ~/.bashrc

So, this is wrong:

> bashrc refers to something that runs in each and every new shell

Because .bashrc doesn't run when you execute a shell script, and doesn't run when you use `bash -c`.

And this is wrong:

> profile refers to something that runs only in interactive shells

Because it does run in non-interactive shells when they're login shells, and because it implies that it runs in every interactive shell, which it doesn't. It only runs in login shells.


Insanely enough, this is set up wrong in Debian and derivatives, where bash_profile sources bashrc as a default from /etc/skel, leading to damning "not a tty" messages because at some point it calls some tty requiring command unconditionally.


This explains so many of my problems. Thank you.


https://hackernoon.com/bash-profile-vs-bashrc-vs-bin-bash-vs...

Note that in macOS every new Terminal (tab) opens a login shell, while most GUI Linux environments don't. (In Tmux/screen it depends on the configuration).


There's a graph (generated by graphviz from text description) that shows the flow and files involved for bash, sh and zsh. Yes, it's insane.

https://blog.flowblok.id.au/2013-02/shell-startup-scripts.ht...


I thought macOS always loaded the shell as a login shell by default while most Linux and UNIX load a non-login shell by default.

On a Mac you usually end up adding

    if [ -f ~/.bashrc ]; then
      . ~/.bashrc;
    fi 
To your .profile or .bash_profile.

Just read that part and now I can’t help but question the rest of it before even reading it


I just moved to Catalina, and the fact that zsh has a clear and reasonable standard for startup files made up for the fact that I had to move my shell init to its files.


The way the files are loaded on Bash has a standard.

Apple breaks it, but there is.

Here’s info, https://unix.stackexchange.com/questions/170493/login-non-lo...

ZSH follows the same for login/non-login but I don’t see it for interactive.


If you do, it will even load it for non-interactive shells.

  if [ -n "$PS1" ] ; then
    [ -r ~/.bashrc     ] && . ~/.bashrc
    [ -r ~/.bash_login ] && . ~/.bash_login
  fi


Yep. It’s a mess frankly.


It sounds right to me, when running thru cron for example, I need to load env vars as part of my script startup otherwise even path is missing.


> I'm not an expert on bash exactly though I am a heavy shell user (POSIX shell for scripting) but this part doesn't sound right. When is .bashrc ever executed when bash isn't interactive?

Never.

TFA has got it wrong.


.bashrc would get executed when you run something in cron. Cron runs non-interactive shell sessions.


I tested this and this is not the case. My .bashrc does a lot of things such as custom completions that are expensive that I would not want run by anything else other than an interactive shell. It also has return at the end so if anything I don't know about adds stuff to it, it won't get executed. This would break other scripts loading .bashrc as well. So as far as I can see this is false.


From the manual:

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.

So interactive, non-login shells only.

But also:

When invoked as an interactive shell with the name sh , bash looks for the variable ENV, expands its value if it is defined, and uses the expanded value as the name of a file to read and execute. [A] shell invoked as sh does not attempt to read and execute commands from any other startup files

So only when invoked as bash, not as sh.


Thank you, very helpful. That explains why I have to have my .bash_profile source .bashrc for use with tmux, as it executes bash as a login shell. I knew I had to have this but wasn't 100% on why until now. Note to self, RTFM!


scp executes .bashrc if I recall correctly. Any echo in .bashrc broke scp for me in the past.




Consider applying for YC's Fall 2026 batch! Applications are open till July 27.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: