I’m used to source user-specific ~/.bashrc file when starting interactive Bash shell. However, surprisingly, my freshly-installed NixOS 22.05.3893.040c6d8374d (Quokka) does not want to do it automatically.
Is there any reason behind that?
What should I do to allow users to source their .bashrc files and not use Home Manager for that?
Are you sure .bashrc is not sourced at all, e.g. rather than breaking early on because of an incompatibility? Because you shouldn’t need to do anything to have it sourced (assuming you don’t pass --norc to bash somehow). I would start by sticking an echo to the very beginning of .bashrc to verify if it’s actually evaluated.
You’re invoking it as a login shell there, which explicitly does not source ~/.bashrc. From the bash man page:
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 , and ~/.profile , in that order, and reads and executes commands from the first one that exists and is readable. The –noprofile option may be used when the shell is started to inhibit this behavior.
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 –rcfilefile option will force bash to read and execute commands from file instead of /etc/bash.bashrc and ~/.bashrc .
Strangely, there are some references to bashrc in your logs. I suspect they’re loaded by a profile for one reason or another. I’m also not sure if -x is a good tool for tracing whether bash sourced initial login files, not wholly convinced it’s doing that through commands that will be logged there.
By default the shell that you load into from the TTY is a login shell as well, which is probably what’s confusing you. Some people manually add a source ~/.bashrc to their ~/.bash_profile, you may have done so previously and forgotten about it. Or you just rarely use the TTY directly, terminal emulators usually run non-login interactive shells. Saw the SSH reference, sorry, skimmed past that. No idea why your SSH session isn’t reading bashrc (I forget if those are login shells too, or if you customize that behavior, or what), but your test definitely should not.
Bash config always seems trivial until you spin up a new machine
I perpetually find the squishy norms around shell init files confusing. They also get handled differently on macOS (though IIRC it’s more about how macOS vs linux handle the notion of login shells?), and people with multiplatform dotfiles can further subvert the platform norms.
If that changed, it hasn’t been the case since around late 2019. To my knowledge I’ve never had a .bash_profile in any of my NixOS systems. I think I’d have noticed, I use zsh and hate dotfile clutter in my home directories.
Also don’t think there are any options for skel directories, and I don’t think there’s a default one.
Might make sense to spin up a VM with your config and build an older nixpkgs commit just to confirm?
Wayland sessions don’t currently load your shell init files, depending on whether you use a login manager/which login manager you use, though, which I suspect is more likely the root cause of that ticket?
I found this topic when investigating why my .bash_history recently started being reset to a tiny number of lines once in a while. Based on the above I’ve done a simple test, and it turns out ssh 127.0.0.1 does not source ~/.bashrc. Verified this by adding set -x on top of ~/.bashrc, and nothing extra was printed when SSH-ing in. This means HISTFILESIZE and HISTSIZE are both set to tiny values of 500.
I’ve also verified that SSH sessions are interactive:
$ echo $-
$ ssh 127.0.0.1
Last login: Fri Sep 15 20:05:29 2023 from ::1
$ echo $-
Something must’ve changed recently (as part of or since 23.05 would be my guess), because I regularly SSH between my machines, and this didn’t use to be a problem.
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, and ~/.profile, in that order, and reads and executes commands from the first one that exists and is readable.
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.
The ssh shell is an interactive login shell, so it behaves according to the first paragraph, i.e. it should not execute your .bashrc. This is expected and documented behavior, and has been for decades.
Login shells are shells that start your session on a given computer, and are not subshells of another shell. This is pretty much only those launched by ssh or your tty login, so never the shells in your emulator in a graphical session. Interactive shells are those attached to terminals where you are interactively typing, and may also be login shells.
The reason these operation modes are often confused is because people rarely know the difference between login and interactive, and because debian’s default skel for some cursed reason loads .bashrc from .profile, defying bash’ default behavior and potentially breaking non-bash shells.
NixOS has never screwed with this behavior. I imagine some people copy around their old debian shell init files, and then get confused when behavior changes if they rewrite them from scratch.
macOS, at least in the official Terminal app, also plays a role in the confusion here by launching login shells.
Not sure about the sanity of the approach, but at some point I got annoyed and decided to just set up .bash_profile to source .bashrc, and set up .bashrc to bail out after basic PATH setup when it isn’t interactive.
I think that’s pretty reasonable for user config. It’s 2023, nobody actually uses .bash_profile to start daemons anymore, that’s for systemd user sessions. I do think the upstream bash behavior deserves a rework, precisely because it’s so confusing, but I don’t think debian is doing us any favors by doing so at a distro level.
I guess the question then becomes "LOL WTF Bash, where am I supposed to set HIST*SIZE and the like so that an SSH session works the way 98.7253% of users expect it to - that is, the same as just opening a bloody terminal on the relevant machine?
I’m sure that’s a hypothetical question, but I like @abathur’s suggestion a lot.
The problem is that we want to execute the interactive config (which should probably be in .bashrc) in interactive login shells, but it’s not done by default.
For completeness sake, and for those who may land here in the future, I would probably do this personally:
# Set up any env vars, etc.
[[ $- == *i* && -f "$HOME/.bashrc" ]] && source "$HOME/.bashrc"
And then make sure $PATH and other variables are set correctly on session login, and carried over into all interactive shells I care about, instead of modifying them every time I launch an interactive shell. Mainly to keep modifications post session-setup correctly reflected in subshells, as might happen with wayland/X init scripts joining the mix.
But @abathur 's lazy suggestion is nice if you don’t trust env vars to carry everywhere properly (e.g. in emacs shells):
# Run things that should happen on user login, but before
# X/wayland is started, e.g. star your emacs daemon maybe,
# though really you should use systemd for these things
# Set up any env vars, etc.
[[ $- == *i* ]] && exit 1
# Do interactive shell initialization
Maybe this should be bash’ default behavior, but it’s overall still brittle. Really someone needs to sit down and think through the whole modern session init design, all the way from tty login over systemd units to wayland session, and then raise a crusade of PRs to all projects involved…