9

My Understanding

  • there are no rc files called for non-interactive/non-login shells; for example, those run by cron
    (I don't know this for certain and would lean on the community's expertise)

  • non-interactive shells require the BASH_ENV environment variable to be set, which enables to set it to a particular rc file (e.g., BASH_ENV=$HOME/.bash_profile)

The Hope

I'm not certain about the plethora of rc files available, so am curious if there is ones that I'm not familiar with. Hoping to find an rc file that meets the following conditions:

  • called regardless of interaction/login mode so global shell environment variables can be set in one place
  • performs more like csh/tcsh
2
  • Some processes create their own environment such as cron and sudo.
    – fd0
    Commented May 3, 2017 at 16:39
  • And I don't know if this is limited to Ubuntu, but Ubuntu has system-wide environment variable settings: help.ubuntu.com/community/… , which mentions sudo. For instance, I would expect cron to have $USER already set, but instead it sets $LOGNAME -- I think (can't remember exactly)
    – vol7ron
    Commented May 3, 2017 at 17:43

2 Answers 2

8

The answer to your specific question is that often only /etc/bash.bashrc (or /etc/bashrc) is loaded.

There seem to be a couple of ways to address this, most are workarounds unfortunately. In no particular order of preference:

Fake a login

Logins run /etc/profile and often you can place your custom scripts in /etc/profile.d/*.sh

Wrap it in a bash login

Sometimes it is easiest to trigger a login, i.e.

echo "do whatever $PATH $BASH $PS1 $0"

becomes

bash -lc 'echo "do whatever $PATH $BASH $PS1 $0"'

Manually load the profile

Do what logins do, manually load the profile

source /etc/profile;echo "do whatever $PATH $BASH $PS1 $0"

Edit global environment variables

For simple variables you can add to /etc/environment see Ubuntu System-wide_environment_variables but variable expansion does not work

THING_HOME="/opt/thing"
PATH="$PATH:/opt/thing" # this will NOT work

For PATH you could append to it e.g. sudo sed -i 's#PATH=\"[^\"]*#&:/opt/thing#' /etc/environment

Edit all bash shells

You can add to /etc/bash.bashrc (or /etc/bashrc) however this normally exits early if non-interactive so you need to hack your additions on before:

# If not running interactively, don't do anything
[ -z "$PS1" ] && return

Do none of these

  • Consider symlinks if you are trying to add something to the PATH
  • Consider making your programs/scripts modify their own environment
  • Systemd has EnvironmentFile and Environment e.g. systemctl edit --full cron.service

I am interested in hearing if anyone else has better workarounds!

0

I recently wanted to coax bash into behaving as though some particular source file was 'native' to it, regardless of execution context.

This so that I could form a "dialect" of bash that can be run from a #! ("shebang") and interactively both. I haven't tested it as a login shell yet.

In the end it was quite straight-forward:

  1. Separate file for the to-be-sourced bash script
  2. envsubst the absolute location of this file into a runner that is copied into a directory in PATH:

SOURCE="$(realpath special_bash)" envsubst <./special_bash_runner_source >/usr/bin/special_bash

  1. The runner itself:
#!/bin/sh
# optional check to ensure bash is not called with two `--rcfile` or `--init-file`:
# echo "$@" | grep -F -e rcfile -e init-file >/dev/null && echo '--rcfile and --init-file parameters not supported' 1>&2 && exit 99
ENV="$SOURCE" BASH_ENV="$SOURCE" bash --rcfile "$SOURCE" "$@"

Then, to prevent nested execution (considering my script applied destructive transformations to the bash execution environment):

! [ /bin/bash = "$SHELL ] && echo "runner only works in a bash shell, exiting" 1>&2 && exit 1
SHELL=/usr/bin/special_bash

(This one could perhaps use a little more love.)

And to top it off, interactive session detection:

[ -t 0 ] && [ -t 1 ] && set +e

(I have set -e in scripts by default, but this is too impractical for interactive sessions.)

With this I can do both:

$ special_bash

... to drop into an interactive special_bash session, and I can also do this:

#/usr/bin/env special_bash
iffffffffffffff testerontario -z ""; and_only_then
  ... <more silly bash dialect>
fffffffffffffff

You must log in to answer this question.

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