I've been doing Unix for 30 years now and for the last 27 I've had all these scripts wired together. Or rather I have one script, then the others execute it.
I get in theory why I'd want interactive login shells to have a fancier / more complex environment than others. Maybe I should care more about optimizing startup time of non-interactive shells. But really, who has the time to figure that stuff out?
Put env vars in bash profile and functions, aliases and other non-env (completion, nvm, rvm etc) in bashrc.
Put the latter into the former and they aren't inherited. Put the former into the latter and path appends and other non-idempotent edits to env vars don't work correctly. Though I personally use some functions to make sure my path edits are idempotent for ease of iteration when editing.
That is... helpful, in a sense. I mean, it's not the fault of the graphic that it's so convoluted.
But can someone explain why it has to be this convoluted? If I parse it correctly, there is no single place where I could place an alias and have it be available in all bash invocations (e.g. green and yellow arrow don't go through any common files). Without resorting to sourcing one from another, that is.
The former image is from a blog post entitled "Shell Startup Scripts" [0] which I've just submitted [1] separately because it's so much more informative (it's been posted to HN previously but never really provoked much discussion).
That blog post was my primary reference after zshall(5) when I decided to blow away the years of cruft I'd built up, start over, and rewrite my (Zsh) shell init files from scratch -- and I've been amazed at how much more organized and manageable it all is since then!
Prior to switching to Zsh, I had gotten to the point of just dumping everything in one file and making sure it was sourced (by bash) in all instances.
I try to maintain a cross platform set of bash startup scripts but the biggest problem is that macOS and Linux don't follow the same rules.
.bash_profile is only supposed to run after logging into an interactive shell, and .bashrc is for every new shell.
But macOS runs .bash_profile every single time you open a new shell window, so you have to do some creative scripting to make it do what you want to do.
remove the - in front of bash in the settings of Terminal.app. Then the terminal does not run a login shell but an interactive shell. You might have to add -i after bash for that.
I generally use .profile as a place to declare configuration common to all shells, mostly environment variables like PATH and GOPATH and the XDG_*_PATH variables. Then I use shell specific files like bashrc and zshrc to configure shell-specific things, and make sure to source .profile.
I use .profile for exporting environment variables and .rc for everything else.
The rationale is that exported env variables are inherited (and I most probably don't want them overwritten by child interactive shells reading .*rc) and other things (e.g. aliases) aren't and I probably want them set for every interactive shell.
> The primary thing to understand is that the rc files are for all shell invocations while the profiles are strictly for interactive shells. An interactive shell is where you (end user) types the command while an non-interactive shell is when shells are launched by other programs such as a script with #!/bin/bash as SHEBANG value
So, what are use cases in which a non-interactive shell is launched? One example is a cron jobt that runs every night. It's basically the "cron" process executing a command which could be a bash script. Another example would be startup scripts that launch background processes and services which you'd find in /etc/system.
There's a distinction between interactive v. non-interactive and login v non-login as well [2]
Typical issue would be adding something to your PATH variable in .profile, having your script work just fine in a shell, but having it fail when you run it as a cron job because .profile never gets sourced by cron.
These days, I fail to see any need to put anything in the .bashrc file.
If there is some non-interactive use of bash, I just want a clean environment, and everything scp or ssh needs should be on the standard $PATH.
There's no point in putting anything in .profile either, because if I am running an interactive session, I will be using bash. I don't care about the config for dash or whatever.
And any scripts should completely specify their required functions, $PATH and whatever inside the script itself. Use 'source' to pull in common functions.
In Linux, processes scheduled in cron, systemd or other schedulers don't require and may sometimes have issues with the customizations in login scripts for interactive sessions. Login scripts may expect input from the user keyboard, or may depend on environment variables that exist when a login script is executed, but not when nonlogin scripts execute.
Just don't try to apply anything you learn here to GitHub Actions images because the environments are kind of wild and broken across OSes and your scripts will not be triggered the way you would otherwise expect them to...
These rules of thumb are useful, but in the real-world I find the use of startup files to be very inconsistent across different platforms. Oftentimes I someone will override the default behavior, sourcing files in different conditions or order than you would expect. There's really no substitute to reading all the startup files in /etc and ~. Sometimes it's even necessary to inspect the binary itself when you find that a shell has been compiled with non-standard paths.
i'm a huge fan of bashrc_dispatch, which splits your bashrc into versions that run either all the time, when non-interactive, when interactive, or for login shells, as well as gives you functions like `shell_is_osx`, so you can share your configs across multiple operating systems:
[+] [-] NelsonMinar|5 years ago|reply
I get in theory why I'd want interactive login shells to have a fancier / more complex environment than others. Maybe I should care more about optimizing startup time of non-interactive shells. But really, who has the time to figure that stuff out?
[+] [-] barrkel|5 years ago|reply
Put env vars in bash profile and functions, aliases and other non-env (completion, nvm, rvm etc) in bashrc.
Put the latter into the former and they aren't inherited. Put the former into the latter and path appends and other non-idempotent edits to env vars don't work correctly. Though I personally use some functions to make sure my path edits are idempotent for ease of iteration when editing.
[+] [-] m463|5 years ago|reply
[+] [-] arminiusreturns|5 years ago|reply
https://blog.flowblok.id.au/static/images/shell-startup-actu...
https://i.stack.imgur.com/6LQgh.png
[+] [-] MauranKilom|5 years ago|reply
But can someone explain why it has to be this convoluted? If I parse it correctly, there is no single place where I could place an alias and have it be available in all bash invocations (e.g. green and yellow arrow don't go through any common files). Without resorting to sourcing one from another, that is.
Is there a method to this madness?
[+] [-] jlgaddis|5 years ago|reply
That blog post was my primary reference after zshall(5) when I decided to blow away the years of cruft I'd built up, start over, and rewrite my (Zsh) shell init files from scratch -- and I've been amazed at how much more organized and manageable it all is since then!
Prior to switching to Zsh, I had gotten to the point of just dumping everything in one file and making sure it was sourced (by bash) in all instances.
--
[0]: https://blog.flowblok.id.au/2013-02/shell-startup-scripts.ht...
[1]: https://news.ycombinator.com/item?id=24881944
[+] [-] francislavoie|5 years ago|reply
[+] [-] LeoPanthera|5 years ago|reply
.bash_profile is only supposed to run after logging into an interactive shell, and .bashrc is for every new shell.
But macOS runs .bash_profile every single time you open a new shell window, so you have to do some creative scripting to make it do what you want to do.
[+] [-] m463|5 years ago|reply
[+] [-] funcDropShadow|5 years ago|reply
[+] [-] Spivak|5 years ago|reply
[+] [-] adrusi|5 years ago|reply
[+] [-] praptak|5 years ago|reply
The rationale is that exported env variables are inherited (and I most probably don't want them overwritten by child interactive shells reading .*rc) and other things (e.g. aliases) aren't and I probably want them set for every interactive shell.
[+] [-] TwoNineFive|5 years ago|reply
[+] [-] nickthemagicman|5 years ago|reply
One interesting thing I discovered was there are system-wide profile and bash profile scripts.
/etc/profile /etc/.bashrc
In case you need to set these for every account.
[+] [-] CaptArmchair|5 years ago|reply
> The primary thing to understand is that the rc files are for all shell invocations while the profiles are strictly for interactive shells. An interactive shell is where you (end user) types the command while an non-interactive shell is when shells are launched by other programs such as a script with #!/bin/bash as SHEBANG value
[1] https://www.golinuxcloud.com/bashrc-vs-bash-profile/
So, what are use cases in which a non-interactive shell is launched? One example is a cron jobt that runs every night. It's basically the "cron" process executing a command which could be a bash script. Another example would be startup scripts that launch background processes and services which you'd find in /etc/system.
There's a distinction between interactive v. non-interactive and login v non-login as well [2]
https://dev.to/bijaykumarpun/linux-shells-interactive-non-in...
Typical issue would be adding something to your PATH variable in .profile, having your script work just fine in a shell, but having it fail when you run it as a cron job because .profile never gets sourced by cron.
[+] [-] ansible|5 years ago|reply
If there is some non-interactive use of bash, I just want a clean environment, and everything scp or ssh needs should be on the standard $PATH.
There's no point in putting anything in .profile either, because if I am running an interactive session, I will be using bash. I don't care about the config for dash or whatever.
And any scripts should completely specify their required functions, $PATH and whatever inside the script itself. Use 'source' to pull in common functions.
[+] [-] unknown|5 years ago|reply
[deleted]
[+] [-] devnull255|5 years ago|reply
[+] [-] toast0|5 years ago|reply
That's not necessary or desirable in a non-login context.
[+] [-] mehrdadn|5 years ago|reply
[+] [-] brbsix|5 years ago|reply
[+] [-] beaugunderson|5 years ago|reply
https://github.com/gioele/bashrc_dispatch
[+] [-] RunningDroid|5 years ago|reply
[+] [-] mstade|5 years ago|reply
[+] [-] vaccinator|5 years ago|reply