Shell login - profiles and scripts

From Helpful
Revision as of 14:47, 15 November 2017 by Helpful (Talk | contribs)

Jump to: navigation, search
Linux-related notes
Linux user notes

Shell, admin, and both:

Shell - command line and bash notes · shell login - profiles and scripts · Shells and execution ·· find and xargs and parallel · screen and tmux
Linux admin - disk and filesystem · users and permissions · Debugging · security enhanced linux · health and statistics · kernel modules · YP notes · unsorted and muck
Logging and graphing - Logging · RRDtool and munin notes
Network admin - Firewalling and other packet stuff ·

Remote desktops
VNC notes
XDMCP notes

This article/section is a stub — probably a pile of half-sorted notes, is not well-checked so may have incorrect bits. (Feel free to ignore, fix, or tell me)

(See also X startup scripts)

This is mostly about bash's behaviour, and tweaking it. It doesn't touch much on shell programming or syntax.

What gets run/sourced when

Portability note: The below mostly details bash / bourne family.

Other shells, say zsh, ksh, csh, tcsh and others, work differently - syntax, escaping notes, but more relevantly, their own additional scripts they source. Some of the below will not be usable in other shells without some adaptation.

In general, you can need to consider the distinction what gets sourced by:

  • login shells
  • interactive shells
  • scripts (usually very little)
  • (primarily for shells) what gets sourced by everyone versus by specific users

Login shell versus interactive shell

This article/section is a stub — probably a pile of half-sorted notes, is not well-checked so may have incorrect bits. (Feel free to ignore, fix, or tell me)

Technically, login/not and interactive/not these are two separate properties, so there are four combinations, though in practice you can often consider them:

  • 'login-interactive' (first on a tty)
  • 'interactive' (not first on a tty)
  • 'script'

  • login shells
    • are those that are first on a tty (or specifically requested to be login)
    • include those launched via /bin/login, e.g. the text-mode hardware terminals
    • include those specifically requested to be login, e.g. bash -l or bash -login (e.g. VNC's .Xstartup often does this)
    • when switching users with
      su - username
      su username
      gives a non-login shell)
      sudo -i
      (-i is short for --login)
    • "when argument zero starts with -", i.e. when you create a link that has its name start with -.
    • interactive login shell, login shell, initial login shell are all the same thing.

  • interactive shells (that is, interactive non-login) refer to those...
    • launched by name
    • graphical terminal programs invoke these by default(verify)
    • invoked using an explicit -i
    • using su, unless you explicitly use - / -l / --login
  • you can check: $- includes i
  • non-interactive (can be login, usually is not?(verify))
    • examples are:
      • A shell running a shell script: that subprocess is always considered a non-interactive shell (even if it can access its tty) (verify)
      • commands invoked via bash -c (verify)
    • these do not implicitly read any configuration files (verify)

Check for interactive or not:

look for an i in the special bash variable $-, e.g.
[[ $- == *i* ]] && echo 'Interactive' || echo 'Not interactive'
# or
case $- in
   *i*) echo 'Interactive' ;;
     *) echo 'Not interactive' ;;
# or, in many shells, checking a variable like PS1

Check for login or not:

Things like shopt will also tell you (login_shell on or login_shell off). In a test, -q is nice
shopt -q login_shell && echo 'Login' || echo 'Not login'
# or leading - in $- (verify)

Distinctions between .bashrc and similar files


This article/section is a stub — probably a pile of half-sorted notes, is not well-checked so may have incorrect bits. (Feel free to ignore, fix, or tell me)
  • /etc is most useful for the shared-with-everyone environment stuff
sourced by: TODO

  • profile is intended to be sourced by login shells
  • /etc/profile
also /etc/profile.d/, ~/.profile
and bash_profile, bash_login -- and similar for other shells
/etc/profile.d/ is functionally equivalent to /etc/profile, it just makes it easier for packages to add/remove their parts
  • /etc/bash.bashrc and ~/.bashrc are intended for interactive shells (e.g. GUI shells, su)
/etc/profile tends to explicitly source /etc/bashrc (and if you have a ~/.profile, it tends to explicitly source ~/.bashrc)
so this is the place for "for every interactive shell you create" stuff.

  • Login shells often have distinct settings/behaviour from non-login shells.
...though for "add to environment" stuff it matters less, because it tends to get inherited everywhere you want anyway (exceptions: security-aware apps may clear/whitelist the environment)
...still makes sense to put most things in bashrc - it's in a single place and goes to all interactive shells (login and non-login)
(it's the stuff that needs to be aware of specific context that's interesting)

  • non-interactive shells (mainly scripts):
...actually do run the bashrc and variants - but those start with
[ -z "$PS1" ] && return
so have no effect in this case.
this means you can use them for things that should go to scripts and interactive shells -- put it before that line.
(removing that line will likely break things)

  • bash_profile versus bashrc:
Each user has their own ~/.bashrc (or an analogue for other shells) that applies to interactive shells
You have .bash_profile (or an analogue for other shells, and some use plain .profile) that applies to login shells (text-mode login, screen)

Neither' (profile or bashrc(verify)) apply to shell scripts

if you need specific environment, source it explicitly from the script (an existing /etc/prpfile.d setup can be quite convenient here)

  • You usually don't need to bother with login and logout rcfiles at all



What files are look for

Portability note: Specific shells will additionally (sometimes instead) look for files specific to them. For example,

bash has .bash_profile and others,
tcsh has ~/.tcshrc,
ksh and pdksh have ~/.kshrc,
zsh uses /etc/zshrc, /etc/zprofile, /etc/zlogin, /etc/zlogout, /etc/zshenv, ~/.zprofile, ~/.zshrc, ~/.zlogin, ~/.zlogout, ~/.zshenv,
and so on.

Most sh-family shells (most of them: it includes sh, bash, zsh, csh, tcsh, pdksh, ksh, jsh and others (verify)) check for:

 file                    used by what?            used when / notes
------------------  ------------------------  ----------------------------
/etc/profile               sh family            login shells at login

/etc/profile.d/*.sh        sh family            from a loop placed in /etc/profile
                                                other extensions in the directory are for other shells

~/.login                   sh family            login shells at login
~/.profile                 sh family            login shells at login
~/.logout                  sh family            login shells at logout

/etc/bashrc                                     I've mostly seen this sourced explicitly
or                           bash               The point seems to be to put environment in /etc/profile,
/etc/bash/bashrc                                  functions and aliases in here.
~/.bash_login                bash               login shells at login 
~/.bash_profile              bash               login shells at login

~/.bashrc                    bash               interactive shells

~/.bash_logout               bash               login shells at logout
                                                not used very often


  • not all sh-family shells necessarily check for all of these. Don't count on it.
  • There seems to be no home-directory file (that is not shell-specific) that is guaranteed to be used.
  • Interactive shells (including various graphical terminals) may not read /etc/profile at all. Some setups are tweaked to do so intentionally, to make it easy (relatively) system-wide point of inclusion, but don't count on it. Or fix it (in your own profile, and admins could do so via skel)
  • While you may be able to count on /etc/profile, ~/.profile is less sure(verify)

If you want to know what exactly your specific shell is doing and sourcing, you can watch it open files with something like

strace -e trace=open  bash -l -c echo  2>&1 | egrep -v '(/lib|/proc|locale)'
where the -l in this example specifically tests a login shell (-c echo just makes the new shell quit after it does nothing worth mentioning)

See also:

  • this for more bash details.
  • this for more general details.
  • this for details for other shells.

TODO: read:

Related notes

It seems that bash special-cases sshd and rsh.

This matters for sftp, scp, rcp, in that if .bashrc is read outputs anything, this will likely confuse/break these tools.



It seems that this is only ever read by PAM. It reads and sets the contents in the environment, before loading your shell.

This means

  • it is useful environment setting for all shells, not just sh-like shells (so can be a good alternative to /etc/profile).
  • it is not a shell script. No expansion and such, mostly just key=value lines
    • no PATH=$PATH:/and/more/. But when it's the first thing that gets read, you typically don't need to.
  • This file only gets applied when logging in (a mechanism that uses PAM). Running bash (-i or -l) won't do it. The next graphical login, will do it. A ssh to localhost will do it.

Potentially useful fragments for your bashrc and bash_login

Note: The difference between bashrc and bash_login is that bashrc is for interactive shells (including xterms, I believe), and the second for login shells (including screen windows).

In practice you may want to put things into both, or create a script of common things that you call from both.

grep results in color

When it is not the system default, you can get grep to output colors when it is the main command (not when used in a pipe, based on autodetection), using:

export GREP_OPTIONS='--color=auto'

If you want it even in pipes you can set it to always. Can be nice e.g. for less, but not everything you pipe into understands the escape codes. Arguably always is best used in aliases, not as a default.

You can change the colors it uses using GREP_COLORS (or the deprecated GREP_COLOR), in which you can set the color of various different parts of the grep results; see the man page.

History stuff

Searching the history

Ctrl-R is usually what you want (searches from most recent to older)

If you want the next match, press Ctrl-R again.

Note that if you press enter you immediately execute the command; you often want to press an arrow key or Tab instead.

Cleaner history

You can specify things that should not be logged, which can be handy when arrow-upping for recent interesting commands as well as using Ctrl-R to search it.


export HISTIGNORE="&:cd:exit:mutt:ls:[bf]g *|[bf]g"

In this example:

  • The & means/matches 'the previous line', which avoids adjacent duplicates from being logged.
  • ls, cd, exit, and mutt are matched exactly, not when they have arguments (I e.g. like to have my previous 'go to working directory' commands in my history)
  • fg, and bg are ommitted both when they appear with and without arguments

Further details

This article/section is a stub — probably a pile of half-sorted notes, is not well-checked so may have incorrect bits. (Feel free to ignore, fix, or tell me)

HISTIGNORE (see above)


  • a colon-sperated list of options that further controls how and what to save
  • ignorespace: Lines that start with a space are not saved
  • ignoredups: causes lines matching the previous history entry to not be saved. A value of
  • ignoreboth: shorthand for ignorespace:ignoredups
  • erasedups previous lines matching current line are removed from history before the current line is saved.


  • the amount of recent history that a bash process keeps
  • default: 500
  • if unset / empty string, it has no limit


  • the file that the the running shell writes its own history to (when it exits)
  • default: ~/.bash_history
  • unsetting means 'don't save this shell's history'


  • the amount of a shell's own history, in lines, to write to HISTFILE (when the running shell exits)
  • default: value of HISTSIZE, unless set
  • unsetting it means 'don't truncate after saving' (you may want to set up log rotation)
  • 0 means truncate to empty file

histappend (shell option) - append to central history instead of replacing it

The basic behaviour:

  • On startup, bash loads HISTFILE, apparently after truncating it to the most recent HISTFILESIZE lines
  • each line is saved to a specific shell's HISTCONTROL and HISTIGNORE
  • When it exists, bash
    • writes its own in-memory history to HISTFILE (overwrite/append according to histappend)
    • then truncates that file to have at most HISTFILESIZE lines (unless HISTFILESIZE is not set)

You can force bash to write to and update from HISTFILE using history -a; history -n

I doubt there is file locking going on, so PROMPT_COMMAND=’history -a; history -n’ might lead to occasional clobbering(verify)

Note on export, setenv, etc

This article/section is a stub — probably a pile of half-sorted notes, is not well-checked so may have incorrect bits. (Feel free to ignore, fix, or tell me)

In bash, export replaces a variable in the current environment. Other shells may use setenv or set.

#usually written as:
export PATH=$PATH:/bla/bla
#but equivalent to a local set followed by an explicit export
export PATH

export differs from basic assignming to named variables mostly in that exports inherit to new (sub)environments. (I remember there being some pesky details. I should check up on them.)

Useful things to export include:

  • path to look for things to execute (PATH)
  • program defaults (e.g. GREP_COLOR=auto, LESS="-aXz-5j3", etc.)
  • programs' home directories (eg. GMT_HOME, GRASS_HOME, JDK_HOME)
  • an added directory to have private libraries (LD_LIBRARY_PATH)
  • compiler options (CFLAGS, CPPFLAGS, LDFLAGS for adding additional include and library paths when you want to compile things)
  • things listed below:

Setting PATH

Fairly simple. To add /etc/local/bin/myprogrambins/ and your $HOME/bin to the PATH, for example, do:

export PATH=$PATH:/etc/local/bin/myprogrambins/:$HOME/bin

This preserves the current path and appends the new one. It is a safe default to add to the end of this list in case of name collisions; the first match in the list will be used. This can be exploited for good (perhaps sneaking in colorgcc as default gcc behaviour) and evil (many other cases).

It is not advised to do:

export PATH=$PATH:.

...just to get windows/DOS-like behaviour in that you can run executables from the current directory without having to append a ./. You may get randomly strange directory-dependent behaviour. Doing this ranges from useful-when-careful to annoying to a potential security problem.

Terminal type

This article/section is a stub — probably a pile of half-sorted notes, is not well-checked so may have incorrect bits. (Feel free to ignore, fix, or tell me)

There have been various terminals over the years, with varying capabilities. Consider

  • terminal hardware, those heavy plastic things and
  • terminal software, which includes
    • remote logins (e.g. SSH)
    • local/remote graphical logins (xterm, rxvt, gnome-terminal, konsole, OSX terminal, etc.)
    • terminal hosters/proxies (e.g. screen, tmux, hurd)
    • specific terminal software (consider e.g. cygwin, windows telnet)

Everything worth anything has VT100 compatibility, as it became the de-facto basic set of features.

Most things used now have more to add, but may do it in very specific ways. In pratice, this means we need a terminal to tell us what it is, whether they support a particular feature (say, color, scrolling back, drawing), and how to use it with them.

In *nix, the client advertises most of its capabilities by setting a name in the TERM environment variable. A name maps to a set of features, so the commonly used names don't really mention what a terminal is, but what it supports (which also means you should only set a TERM you the terminal emulator actually supports). (on *nices this is handled via termcap).

Some TERMs:

  • vt100 if all that's supported is the most basic vt100
  • xterm is a basic shell under X
  • rxvt is a more specific X shell, with a few more capabilities. There are different sets for gnome-terminal, konsole, and others. Mostly, these are set by those programs, so you rarely deal with them
  • screen is what each term in a screen gets. Seems to be fairly basic VT100, plus some extras?
You can configure screen to report itself as something else, e.g. xterm-color.
screen itself looks for a termcap entry called screen.$TERM
  • linux is what my text-mode shells have
    • There are variations, like specifically having or not wanting colors.
  • putty (basically VT102 plus a few spected features?)
  • vt100-putty (or putty-vt100?)
  • putty-256color

...and a bunch OS-specific, and many hardware-specific ones.

Look at your /etc/termcap

Some pragmatics:

  • If F1..F12, numpad keys, or such don't work (produce garbage), you probably need to tweak TERM
  • PuTTY defaults to xterm. If shelling to linux, you may be better off using linux (I had troubles with various keys that were fixed this way). putty may work even better (verify)
  • if you tweak things in login scripts, TERM tests should often be 'starts with', not 'is', because variations tend to be -tacked-on

You can change program behaviour based on TERM values. For example:

case $TERM in
       PS1="[fancy term] \u on \h \$ "
       alias ls='ls --color=auto '
       PS1="[other term] \u on \h \$ "


  • applications may also look at TERM to choose what to do, in particular if they do colors or fancy drawing.

Some applications may work better when forced/restricted to behave according to a specific TERM. For example,

alias mc='TERM=xterm mc'

...which is also how I discovered (without logging out and in a bunch) that mc seems to work better with putty than linux.

setting your prompt

(See also e.g. [1])

You usually see what is set in PS1, and you see PS2 if you have multi-line strings and the sort. You're not likely to ever see PS3 or PS4.

It looks like the internal prompt variables (user, host, working directory, date, time, and things like \$; see PROMPTING in man bash) and escapes are evaluated after each shell command you give, while not everything is, and possibly not under all conditions. See the PROMPT_COMMAND for a workaround.

Funky things

Note on using/printing escapes

You can use escape sequences to give ANSI color commands, set the xterm title, move/save/restore the cursor, command a wrapping screen, and other such things.

Note on \[ and \]

Bash and some other shells (which?(verify)) treat
as "from here to a
I shall interpret escapes"
, so that's where you usually put them.


  • These ranges are not counted as printable characters (shouldn't be), which matters in line wrapping behaving sensibly.
  • When you take take values from somewhere to be displayed as part of the prompt (expansion of hostname, cwd, etc.), you want values outside such a range, both for correct wrapping and to avoid strange interactions. If you want to do something to such values, add a sequence before and one after.
  • There are escape sequences that contain
    and those that contain
    . Yes indeed, that's bloody confusing :)

Note on \e versus \033

is a shell-specific (probably bash-specific (verify)) way of saying "I want a literal ESCape control character here." A more compatible and slightly harder to read alternative is
(ESC is 033 in octal, 1B in hex, 27 in decimal) Similarly,
is an alternative to

If you want to experiment with escapes, you may want to know that you can force echo to interpret escapes by using -e, and sometimes -n, 'don't append newline' ). Note however that echo doesn't know \[ and \].

Funky things: Setting the shell's title

ESC, ], 0, ;, titlestring, BEL

The text inside is interpreted by teminals that understand titles, such as most graphical terminals.

For example, you could prepend this to your real prompt:

for something like

Funky things: setting the screen window's title

ESC, k, titlestring, ESC, \

This is the title you see when you list the screens (using Contol-a "), and can set using Control-A Shift-A.

For a prompt, and with escaping inside a "-quoted string, this works out to, for example:

\[\033k \u, in \w \033\\\]

When you also want to make screen change the X window(-as-in-graphical-window) title according to which screen you are in, you want to tell screen to use its hardline tricks, via .screenrc. See the basic example at screen.


Note that since some older and barer terms may respond badly you should put fancy stuff on a condition, by using something like the following in your bash startup:

case $TERM in
      PS1="\[\033]0;\u on \H\007\]\[\033k\]\w\[\033\\\\\]\u@\H:\[\033[1;37m\]\w\[\033[37m\] \$ "
      PS1="\[\033]0;\u on \H, in \w\007\]\u@\H:\[\033[1;37m\]\w\[\033[37m\] \$ "
      # avoid funky things when you are not sure about the capabilities:
      PS1="\u@\H:\w \$ "

You may want \w (working directory) if you come from windows/DOS or perhaps regardless, though you get used to the non-clutter and remembering where you are. I just decided this format may be useful as it mimics the format scp uses, so it could be useful for copying things about.

If you want to set both screen's window titles and set the window window title, you could e.g.

  • 'user on host' in the window title via PS1
  • set the working directory as the screen window title,
  • use screen's hardstatus feature to prepend <something like>'[0: /var]'</tt> (that is, '[screenwindownum: screenwindowtitle]' ) to the window title.

The result is that screen shows "/var/www" and the whole window shows "[0: /var/www] root on sparrow"

You could have something like:

Extra evaluation

Setting PROMPT_COMMAND allows you to evaluate/execute something before every command -- though note that this is potentially slow.

For example, you could do
PROMPT_COMMAND="echo -n 'Groups: '; id -G -n"

A common use is to change PS1 every prompt, for example...

  • showing the current directory's size
  • make the prompt/title change with variables that aren't part of the \u-style thing bash itself replaces
  • showing the last command's return code ($? in bash)
  • using whoami to show things in red if you're root (though it's simpler to have root's profile/bashrc could just set this explicitly)

You can set the PROMPT_COMMAND variable to

  • a string to evaluate, including the path to a script
  • a bash function, so you can write potentially involved code, such as the following excessive example:
promptFunc() { 
  case $TERM in
      PS1="\[\033[0;32m\][\D{%a, %H:%M}] \[\033[1;34m\]\u@\H\[\033[0m\]:\[\033[1;37m\]\w\[\033[0m\] " ;; 
      PS1="[\A] \u@\H:\w " ;;
  # size of immediate entries (i.e. recursive)
  DIRSIZE=$(ls -l | awk '/^[dlpscb\-][rsS\-][wsS\-][xtT\-]/{totalsize+=$5} END{printf("%d",totalsize)}');
  if [ $DIRSIZE -ge 1073741824 ]; then
    if [ $DIRSIZE -ge 1048576 ]; then
      if [ $DIRSIZE -ge 1024 ]; then
  PS1="${PS1}($DIRSIZE) "
  #append a red [root] if we are root
  if [ `whoami` == "root" ]; then 
    PS1="$PS1\[\033[31m\][root]\[\033[0m\] "
  PS1="${PS1}\$\[\033[0m\] "


  • the fact that ls -l will happen all the time will make changing to directories with very many entries rather sluggish.
  • it might be more robust to do the dirsize based on find ./* -prune -type f -printf "%s\n"

Colored text

ESC, [, colorcode, m.

You will often see ESC as either


Some of the more interesting and better-supported codes (search for Select Graphic Rendition)

  • specify multiple codes at once, separated by ;
  • prepend 3 to a color number: set foreground
  • prepend 4 to a color number: set background
  • 1: bright foreground color
  • 0 clears to default colors/no bright/underline(verify)
useful to start a sequence, because by default you only change the current state
also useful in itself, e.g. to stick at the end of a colored prompt
  • 4: set underline
  • selective clearing:
39 default foreground color
49 default foreground color
22 clears bold
24 clears underline

Color numbers:

  • 0 black (bright black is how you get dark gray),
  • 1 red
  • 2 green
  • 3 yellow (non-bright yellow is brown or orange on some schemes),
  • 4 blue
  • 5 magenta
  • 6 cyan
  • 7 light grey (bright light grey is how you get 'real' white)

Some examples:

  • 35
    sets the foreground to magenta
  • 37;44
    is grey on blue
  • 1;37;44
    is white on blue
  • 1;33;45
    is bright yellow on magenta
  • 0;35
    clears foreground and background flags and colors, then sets the foreground to magenta
  • 0;1;35
    same but with bright magenta
  • 0;1;4;35
    same but also underlined
  • 1;47;30
    is grey (bright black) on white

To play around in a prompt, try something like:

printf "\x1b[0;1;33;45mtest\x1b[0m\n"


Set with


For example, to test support you could do:

for i in {0..255} ; do
    printf "\x1b[38;5;${i}mcolour${i}\x1b[0m\n"

The colors can be summarized

0x00-0x07:  standard colors       (as in ESC [ 30–37 m)
0x08-0x0F:  high intensity colors (as in ESC [ 90–97 m)
0x10-0xE7:  6 × 6 × 6 = 216 colors: 16 + 36 × r + 6 × g + b (0 ≤ r, g, b ≤ 5)
0xE8-0xFF:  grayscale from black to white in 24 steps


A bunch of terms (xterm, konsole, libvte derived including gnome's) will also allow truecolor: 8-bits-per-channel RGB foreground and background:



printf "\x1b[38;2;200;200;244test\x1b[0m\n"

See also

setting DISPLAY

Note that it is easy to mess with other logic to this effect, from the system or from ssh -X.

keybinds and convenience settings


aliases, functions

See some examples at Command_line_intro,_some_common_utilities#Shell_aliases_and_functions

Arguably some should be system-wide scripts.

Colored ls

listens to
  • environment variable LS_OPTIONS for whether/when to use colors, probably export LS_OPTIONS='--color=auto'
  • environment variable LS_COLOR for which colors to use

You may prefer to use dircolors for easier debugging of the contents of LS_COLOR. dircolors reads its own configuration file and produces the sh-style/csh-style environment set line you'ld want in your profile.

When fiddling with dircolors and you want to set it within the current shell, you can do something like:
eval `dircolors -b /etc/dircolors`
(the -b is for bash, -c is for csh. This is purely about how to set the environment variable)

There will often be some logic in the system-wide bashrc (or comparable for other shells) that calls dircolors and evaluates its output. It may prefer


and fall back to: (verify)


You can find defaults and examples in various places.

(See also LS_OPTIONS for other ls formatting options. I like -p)


Potentially useful scripting lines

See also Command_line_and_bash_notes#Shell_conditionals_and_scripting for more general sh/bash syntax notes

"stop now if we don't have this command"

tl;dr you want something like:

command -v pidof >/dev/null || { echo "cannot find pidof, aborting."; exit 1; }

While which seems the obvious choice, it is not as well behaved as you think.

There are other things that effectively do the same, that are shell builtins (so also avoid a process). If you want to support at least bash and <tt>sh, then command -v seems best behaved (defined by POSIX).

(Thanks to this stackoverflow summary)

error/default value if not specified

See Command_line_and_bash_notes#Error_if_not_set

Other shell tricks

special home directory files


Various mail daemons can be configured to look for this file when email is delivered to an account. If the file exists, the contents are treated as the mailboxes and/or email addresses to deliver the mail for.

It is faily common to forward(-and-delete) to a single remote email address, though you can also leave a copy in the account, etc.

See also:


This article/section is a stub — probably a pile of half-sorted notes, is not well-checked so may have incorrect bits. (Feel free to ignore, fix, or tell me)

You can suppress the login banner by placing a file named .hushlogin in your home directory.

This seems a convention followed by various motd logic, but not by everything.

Other bash notes

Special variables

This article/section is a stub — probably a pile of half-sorted notes, is not well-checked so may have incorrect bits. (Feel free to ignore, fix, or tell me)
$0	           script name
$1, $2, $3, etc.   first argument, second, third, etc. You may prefer ${1}, ${2}, etc.
$*                 List of all variables entered at the command line ($1 onwards; no $0)
$@                 similar to $* - differs how?  Peferable over $* ?
$#                 number of command line arguments
$$                 PID of the current shell
$!                 PID of the most recent (background?) command
$?                 Exit code of the last (foreground/pipe) command 
$-                 current shell options

You may also care about Command_line_and_bash_notes#Conditional_replacement

exit from sourced file

e.g. if [ -n "___SOFTSETONCE" ]; then return; fi