1. Configuration

  • Create a /etc/skel/.bash_aliases file.

cat << 'EOF' | sed 's/^  //' | sudo tee /etc/skel/.bash_aliases > /dev/null
  # Set default editor.
  export EDITOR=vim
  export VISUAL=vim
  # Do not put duplicate lines or lines starting with space in history.
  export HISTCONTROL=ignoreboth
  # Expand aliases in shell scripts and inside vim when using the :! command.
  shopt -s expand_aliases
  # Append to history file, do not overwrite it.
  shopt -s histappend
  # Set history length.
  export HISTSIZE=10000
  export HISTFILESIZE=20000
  export NCURSES_NO_UTF8_ACS=1
  # Disable <Ctrl-d> to prevent accidental log out.
  set -o ignoreeof
  # Don't echo control characters.
  if `tty -s`; then
    stty -echoctl
  fi
  # Show user and hostname in green, show working directory in blue.
  # The "\[\e]0;\u@\h\a\]" string is used to change the PuTTY window title.
  # It will also get rid of the annoying "Thanks for flying Vim" title.
  PS1='\[\e]0;\u@\h\a\]${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
  # Alias definitions.
  if [ -f ~/.bashrc_aliases ]; then
    . ~/.bashrc_aliases
  fi
EOF
  • Create a /etc/skel/.bashrc_aliases file.

cat << 'EOF' | sed 's/^  //' | sudo tee /etc/skel/.bashrc_aliases > /dev/null
  # A trailing space in the alias value causes the next word to be checked
  # for alias substitution when the alias is expanded. E.g. "sudo dir /".
  alias sudo='sudo '
  # Several aliases for list command.
  alias vdir='ls --color=auto --show-control-chars -l'
  alias dir='ls --color=auto --show-control-chars'
  alias ls='ls --color=auto --show-control-chars'
  alias ll='ls --color=auto --show-control-chars -l'
  alias l='ls --color=auto --show-control-chars -lA'
  # Alias for hexadecimal dump.
  alias hex='od -t x1'
  # Aliases for "diff" that ignore case and white space.
  alias diff-c='diff --color'
  alias diff-i='diff -i'
  alias diff-w='diff -w'
  alias diff-iw='diff -i -w'
  # Aliases for "git diff" that ignore case and white space.
  alias git-diff="git difftool -x '/usr/bin/diff' -y"
  alias git-diff-c="git difftool -x '/usr/bin/diff --color' -y"
  alias git-diff-i="git difftool -x '/usr/bin/diff -i' -y"
  alias git-diff-w="git difftool -x '/usr/bin/diff -w' -y"
  alias git-diff-iw="git difftool -x '/usr/bin/diff -iw' -y"
  # Some aliases to prevent making mistakes.
  alias cp='cp -i'
  alias mv='mv -i'
  alias rm='rm -i'
EOF

There is no need to back up the original .bashrc files, because the original ~delta/.bashrc file was copied from /etc/skel/.bashrc and the original ~root/.bashrc file was copied from /usr/share/base-files/dot.bashrc.

# Copy skeleton files to user accounts.
sudo /bin/cp -a /etc/skel/.bash_aliases ~delta
sudo /bin/cp -a /etc/skel/.bashrc ~delta
sudo /bin/cp -a /etc/skel/.bashrc_aliases ~delta
sudo chown delta:delta ~delta/.bash_aliases
sudo chown delta:delta ~delta/.bashrc
sudo chown delta:delta ~delta/.bashrc_aliases
sudo /bin/cp -a /etc/skel/.bash_aliases ~root
sudo /bin/cp -a /etc/skel/.bashrc ~root
sudo /bin/cp -a /etc/skel/.bashrc_aliases ~root
# Change color of root prompt from green to red.
sudo sed -i 's/green/red/' ~root/.bash_aliases
sudo sed -i 's/;32m/;31m/' ~root/.bash_aliases

2. Information

2.1. Check for interactive shell

Enter the following command at a Command Line.

[[ $- == *i* ]] && echo "Interactive" || echo "Non-interactive"

2.2. Check for login shell

Enter the following command at a Command Line.

shopt -q login_shell && echo "Login shell" || echo "Non-login shell"

There is an another way of detecting you are in a login shell. The login process tells the shell to behave as a login shell with the following convention: passing argument 0, which is normally the name of the shell executable, with a - character prepended (e.g. -bash whereas it would normally be bash). You can use the echo $0 command to return argument 0.

When the first character returned by the echo $0 command is a dash or hyphen you are in a login shell. Thus, when echo $0 returns -bash then you are in a login shell. However, when it returns bash you may or may not be in a login shell. This is because when invoking an interactive login shell with the bash --login command, the echo $0 command returns bash instead of -bash.

2.3. The BASH_ENV variable

When Bash is started non-interactively, to run a shell script, for example, it looks for the variable BASH_ENV in the environment, expands its value if it appears there, and uses the expanded value as the name of a file to read and execute. Bash behaves as if the following command were executed.

if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi

2.4. Interactive login shell

An interactive login shell is invoked when you log in on a text console, or through bash --login, or ssh, or su -, or tmux.

[[ $- == *i* ]] && echo "Interactive" || echo "Non-interactive"
shopt -q login_shell && echo "Login shell" || echo "Non-login shell"
bash --login
[[ $- == *i* ]] && echo "Interactive" || echo "Non-interactive"
shopt -q login_shell && echo "Login shell" || echo "Non-login shell"
exit

On Debian GNU/Linux the following files are sourced when Bash is invoked for an interactive login shell.

/etc/profile
/etc/bash.bashrc
/etc/profile.d/*.sh
~/.profile
~/.bashrc

2.5. Interactive non-login shell

An interactive non-login shell is invoked when you start another shell through bash, or dash.

bash
[[ $- == *i* ]] && echo "Interactive" || echo "Non-interactive"
shopt -q login_shell && echo "Login shell" || echo "Non-login shell"
exit

On Debian GNU/Linux the following files are sourced when Bash is invoked for an interactive non-login shell.

/etc/bash.bashrc
~/.bashrc

Note that the /etc/profile, /etc/profile.d/*.sh and ~/.profile files are not sourced.

2.6. Non-interactive login shell

A non-interactive login shell is invoked for example through echo '<command>' | ssh localhost, or bash --login -c.

touch ~/.hushlogin
echo '[[ $- == *i* ]] && echo "Interactive" || echo "Non-interactive"' | ssh localhost
echo 'shopt -q login_shell && echo "Login shell" || echo "Non-login shell"' | ssh localhost
/bin/rm ~/.hushlogin
bash --login -c '[[ $- == *i* ]] && echo "Interactive" || echo "Non-interactive"'
bash --login -c 'shopt -q login_shell && echo "Login shell" || echo "Non-login shell"'

On Debian GNU/Linux the following files are sourced when Bash is invoked for a non-interactive login shell.

/etc/profile
/etc/profile.d/*.sh
~/.profile
~/.bashrc
"$BASH_ENV"

Note that the /etc/bash.bashrc file is not sourced.

2.7. Non-interactive non-login shell

A non-interactive non-login shell is invoked for example through ssh localhost '<command>', or bash -c, or a cron job.

ssh localhost '[[ $- == *i* ]] && echo "Interactive" || echo "Non-interactive"'
ssh localhost 'shopt -q login_shell && echo "Login shell" || echo "Non-login shell"'
bash -c '[[ $- == *i* ]] && echo "Interactive" || echo "Non-interactive"'
bash -c 'shopt -q login_shell && echo "Login shell" || echo "Non-login shell"'

On Debian GNU/Linux the following files are sourced when Bash is invoked for a non-interactive non-login shell.

"$BASH_ENV"

2.8. Packages

The various Bash startup files are provided by the bash and base-files packages.

dpkg -L base-files | grep -i '\/etc' | grep -E 'bash|prof|skel'
/etc/profile.d
/etc/skel
dpkg -L bash | grep -i '\/etc' | grep -E 'bash|prof|skel'
/etc/bash.bashrc
/etc/skel/.bash_logout
/etc/skel/.bashrc
/etc/skel/.profile

~root/.bashrc is copied from /usr/share/base-files/dot.bashrc. ~root/.profile is copied from /usr/share/base-files/dot.profile.

dpkg -L bash | grep -i 'bashrc'
dpkg -L bash | grep -i 'profile'
dpkg -L base-files | grep -i 'bashrc'
dpkg -L base-files | grep -i 'profile'

2.9. Summary

Startup file Interactive login Interactive non-login Non-interactive login Non-interactive non-login

/etc/profile

Yes

-

Yes

-

/etc/bash.bashrc

Yes

Yes

-

-

/etc/profile.d/*.sh

Yes

-

Yes

-

~/.profile

Yes

-

Yes

-

~/.bashrc

Yes

Yes

Yes, but skipped

-

BASH_ENV

-

-

Yes

Yes

There is no proper way to add system wide custom settings without an update of the bash or base-files package overwriting your custom settings. The only way is to use the ~/.bash_aliases file that is sourced in the ~/.bashrc file.

3. Scripting

3.1. Block Comments

Disable Block of Code Using Here Document

In a shell script, one way to disable a block of code is to prefix every line of the code with a '#' to make them into comments. However, we can do it much more efficiently using heredoc with the dummy command ':'. For example, we can disable several lines of code in our shell script:

#!/bin/bash
# disable-with-heredoc.sh

: <<'DISABLED'
echo "This line will not show up in the console.
echo "Neither will this line.
DISABLED

echo "This line will be printed to the console

By turning a block of code into a heredoc and redirecting it to the dummy command ':', we’ve essentially prevented the block of code from executing. We’ve enclosed the delimiter token to escape all the special characters in the content. This is done to prevent any command substitution from being executed, thereby preventing any unintended side effects.