Trying to understand the .bashrc file

So i have been trying to understand the default bashrc file and its a mouthful

#
# ~/.bashrc
#

[[ $- != *i* ]] && return

colors() {
	local fgc bgc vals seq0

	printf "Color escapes are %s\n" '\e[${value};...;${value}m'
	printf "Values 30..37 are \e[33mforeground colors\e[m\n"
	printf "Values 40..47 are \e[43mbackground colors\e[m\n"
	printf "Value  1 gives a  \e[1mbold-faced look\e[m\n\n"

	# foreground colors
	for fgc in {30..37}; do
		# background colors
		for bgc in {40..47}; do
			fgc=${fgc#37} # white
			bgc=${bgc#40} # black

			vals="${fgc:+$fgc;}${bgc}"
			vals=${vals%%;}

			seq0="${vals:+\e[${vals}m}"
			printf "  %-9s" "${seq0:-(default)}"
			printf " ${seq0}TEXT\e[m"
			printf " \e[${vals:+${vals+$vals;}}1mBOLD\e[m"
		done
		echo; echo
	done
}

[ -r /usr/share/bash-completion/bash_completion ] && . /usr/share/bash-completion/bash_completion

# Change the window title of X terminals
case ${TERM} in
	xterm*|rxvt*|Eterm*|aterm|kterm|gnome*|interix|konsole*)
		PROMPT_COMMAND='echo -ne "\033]0;${USER}@${HOSTNAME%%.*}:${PWD/#$HOME/\~}\007"'
		;;
	screen*)
		PROMPT_COMMAND='echo -ne "\033_${USER}@${HOSTNAME%%.*}:${PWD/#$HOME/\~}\033\\"'
		;;
esac

use_color=true

# Set colorful PS1 only on colorful terminals.
# dircolors --print-database uses its own built-in database
# instead of using /etc/DIR_COLORS.  Try to use the external file
# first to take advantage of user additions.  Use internal bash
# globbing instead of external grep binary.
safe_term=${TERM//[^[:alnum:]]/?}   # sanitize TERM
match_lhs=""
[[ -f ~/.dir_colors   ]] && match_lhs="${match_lhs}$(<~/.dir_colors)"
[[ -f /etc/DIR_COLORS ]] && match_lhs="${match_lhs}$(</etc/DIR_COLORS)"
[[ -z ${match_lhs}    ]] \
	&& type -P dircolors >/dev/null \
	&& match_lhs=$(dircolors --print-database)
[[ $'\n'${match_lhs} == *$'\n'"TERM "${safe_term}* ]] && use_color=true

if ${use_color} ; then
	# Enable colors for ls, etc.  Prefer ~/.dir_colors #64489
	if type -P dircolors >/dev/null ; then
		if [[ -f ~/.dir_colors ]] ; then
			eval $(dircolors -b ~/.dir_colors)
		elif [[ -f /etc/DIR_COLORS ]] ; then
			eval $(dircolors -b /etc/DIR_COLORS)
		fi
	fi

	if [[ ${EUID} == 0 ]] ; then
		PS1='\[\033[01;31m\][\h\[\033[01;36m\] \W\[\033[01;31m\]]\$\[\033[00m\] '
	else
		PS1='\[\033[01;32m\][\u@\h\[\033[01;37m\] \W\[\033[01;32m\]]\$\[\033[00m\] '
	fi

	alias ls='ls --color=auto'
	alias grep='grep --colour=auto'
	alias egrep='egrep --colour=auto'
	alias fgrep='fgrep --colour=auto'
else
	if [[ ${EUID} == 0 ]] ; then
		# show root@ when we don't have colors
		PS1='\u@\h \W \$ '
	else
		PS1='\u@\h \w \$ '
	fi
fi

unset use_color safe_term match_lhs sh

alias cp="cp -i"                          # confirm before overwriting something
alias df='df -h'                          # human-readable sizes
alias free='free -m'                      # show sizes in MB
alias np='nano -w PKGBUILD'
alias more=less

xhost +local:root > /dev/null 2>&1

complete -cf sudo

# Bash won't get SIGWINCH if another process is in the foreground.
# Enable checkwinsize so that bash will check the terminal size when
# it regains control.  #65623
# http://cnswww.cns.cwru.edu/~chet/bash/FAQ (E11)
shopt -s checkwinsize

shopt -s expand_aliases

# export QT_SELECT=4

# Enable history appending instead of overwriting.  #139609
shopt -s histappend

#
# # ex - archive extractor
# # usage: ex <file>
ex ()
{
  if [ -f $1 ] ; then
    case $1 in
      *.tar.bz2)   tar xjf $1   ;;
      *.tar.gz)    tar xzf $1   ;;
      *.bz2)       bunzip2 $1   ;;
      *.rar)       unrar x $1     ;;
      *.gz)        gunzip $1    ;;
      *.tar)       tar xf $1    ;;
      *.tbz2)      tar xjf $1   ;;
      *.tgz)       tar xzf $1   ;;
      *.zip)       unzip $1     ;;
      *.Z)         uncompress $1;;
      *.7z)        7z x $1      ;;
      *)           echo "'$1' cannot be extracted via ex()" ;;
    esac
  else
    echo "'$1' is not a valid file"
  fi
}

There are a lot of custom things going on here and i'm wondering what everything does. Some of the things i have managed to google, but some i haven't found the answer to.

These are some that i haven't figured out yet, can anybody explain these?

[[ $- != *i* ]] && return

unset use_color safe_term match_lhs sh

xhost +local:root > /dev/null 2>&1

complete -cf sudo

# Bash won't get SIGWINCH if another process is in the foreground.
# Enable checkwinsize so that bash will check the terminal size when
# it regains control.  #65623
# http://cnswww.cns.cwru.edu/~chet/bash/FAQ (E11)
shopt -s checkwinsize

alias np='nano -w PKGBUILD'

Why do we set colors both here and in the .Xresources?

And then i dont understand the entire color bit, and the set command prompt bit.

1 Like

If it's not an interactive shell, exit this script and return to the script that called it. Otherwise, carry on with whatever follows below.

use_color, safe_term, match_lhs and sh are variables that were set for internal use in this script, and will be unset again so that they are not exported to the running interactive shell, for which this script is an initialization file.

Allow local processes with root privileges to connect to the locally running X server.

Set a shell option that checks the size of the terminal window.

Define an alias ─ the command np ─ which will open up the file PKGBUILD in nano, which is a character-mode editor.

I haven't thoroughly investigated this, but there are two possible considerations...

  1. The .bashrc file isn't only used in terminal windows in the GUI. GNU/Linux, like every traditional UNIX, is essentially a character-mode-driven operating system, on top of which the graphical environment runs as an additional (and structurally optional) layer.

  2. There are circumstances in which .bashrc is not read, for instance if it is not an interactive shell.

There are four types of Bash invocation, which can and do overlap:

  1. An interactive shell.
  2. A non-interactive shell.
  3. A login shell.
  4. A non-login shell.

Each of these has its own protocols for what shell initialization files will be read.

More information can be found in...

man bash
info bash

:slight_smile:

7 Likes

colors is simply a function which will print out escape sequences usable for colored text on terminal. You can safely try it out

$ colors

These escape sequences are used for example in this "command prompt bit" to color the prompt differently for root vs any other user.

1 Like

I have added a shell function to my .bashrc for choosing different colors for my prompt. However, my prompt is also specific to myself, and not everyone might like that style of prompt.

My prompt looks like this... :arrow_down:

[nx-74205:/dev/pts/1][/home/aragorn]
[11:04:46][aragorn] >

It is entirely in bright yellow, except for the ">" character, which is in bright white. What that prompt shows me is...

  • on the first line:
    -- the name of the machine and the (pseudo-)terminal that I'm logged into
    -- the current working directory

  • on the second line
    -- the timestamp
    -- whom I am logged in as

The shell function that I've added to my .bashrc is the following... :arrow_down:

cprompt () {

  if [ ! -z $1 ]
  then
    case $1 in

      "green"  )
         clrprompt="\[\e[1;32m\]\n[\h:\$(/usr/bin/tty)][\${PWD}]\n[\t][\u] \[\e[1;37m\]>\[\e[0m\] "
         ;;
      "yellow" )
         clrprompt="\[\e[1;33m\]\n[\h:\$(/usr/bin/tty)][\${PWD}]\n[\t][\u] \[\e[1;37m\]>\[\e[0m\] "
         ;;
      "blue"   )
         clrprompt="\[\e[1;34m\]\n[\h:\$(/usr/bin/tty)][\${PWD}]\n[\t][\u] \[\e[1;37m\]>\[\e[0m\] "
         ;;
      "pink"   )
         clrprompt="\[\e[1;35m\]\n[\h:\$(/usr/bin/tty)][\${PWD}]\n[\t][\u] \[\e[1;37m\]>\[\e[0m\] "
         ;;
      "cyan"   )
         clrprompt="\[\e[1;36m\]\n[\h:\$(/usr/bin/tty)][\${PWD}]\n[\t][\u] \[\e[1;37m\]>\[\e[0m\] "
         ;;
      "white"  )
         clrprompt="\[\e[1;37m\]\n[\h:\$(/usr/bin/tty)][\${PWD}]\n[\t][\u] \[\e[1;37m\]>\[\e[0m\] "
         ;;
      *        )
         echo
         echo "     The only options available are: "
         echo
         echo "         green | yellow | blue | pink | cyan | white"
         echo
         return
         ;;
    esac
    PS1=${clrprompt}
  else
         echo
         echo "     No color specified."
         echo
         return
  fi

}


export -f cprompt

The reason why I haven't offered red as a color choice for the function ─ which can be used as an actual command ─ is that red is the color used by default for the root shell prompt, and I want to keep that distinction. :slight_smile:

1 Like

I use(d) this color distinction for ages on all things linux I run. This easy visual distinction is indeed very helpful.

1 Like

amazing answer, i tip my hat to you! :tophat:

1 Like

Check out bashrcgenerator.com and terminal.sexy for some customization fun that may help with understanding more here

can i ask you another question, is everything actually needed for the default bashrc file in Manjaro+ because i want to set up my own custom dotfiles that i can use. But i dont want a lot of manjaro specific things in my bashrc file say if i want to use it on a ubuntu system.

Is it okey to clear it?

There is some stuff in there that appears to be specific to Arch and Arch-based distributions like Manjaro, and that you may not encounter in other distributions, but not everything.

The golden rule is either way not to use the dot-files from one distribution in another (and unrelated) distribution, exactly because of potential conflicts.

For instance, one distribution may be declaring a lot of stuff in the system-wide /etc/bashrc ─ in Manjaro, Arch, Debian, Ubuntu and Mint, this is /etc/bash.bashrc ─ and /etc/profile (and/or /etc/profile.d/*), while another one does it via the user's dot-files, and then there is the interaction between ~/.bashrc and ~/.bash_profile, and sometimes even ~/.profile. And then there is all the X11-related stuff like ~/.xinitrc, and so on.

What I would suggest is to put all your own stuff in separate files and then source them from within each distribution's respective ~/.bashrc and ~/.bash_profile, like so... :arrow_lower_left:

# Everything above this line is all distro-specific stuff ↑
# Now we do our own initialization routines here...:

if [ -f ~/my_bash_stuff -a -r ~/my_bash_stuff ]
then
  source ~/my_bash_stuff
fi

# Now we go back to the distro-specific stuff below... ↓

Note that you can also write that little routine in a much shorter way, i.e. :arrow_lower_left:

# Everything above this line is all distro-specific stuff ↑
# Now we do our own initialization routines here...:


[ -f ~/my_bash_stuff -a -r ~/my_bash_stuff ] && source ~/my_bash_stuff

# Now we go back to the distro-specific stuff below... ↓

Personally, I always prefer the more elaborate form, because I sometimes share my scripts with other people, and I want them to more easily understand the logic of the code. Both ways of writing that are however equivalent. If we write it in pseudocode, then the more elaborate form does this... :arrow_lower_left:

if the file ~/my_bash_stuff exists, is a regular file and is readable by me
then
  source the file, i.e. read it into the current shell, 
  as opposed to starting a subshell
the_end

... whereas the second and shorter form logically means this... :arrow_lower_left:

Test whether the condition "the file ~/my_bash_stuff exists, 
is a regular file and is readable by me" is true, and only if 
it is, source the file "~/my_bash_stuff".  
("&&" is a logical AND, and "||" is a logical OR.)

:slight_smile:

1 Like

yet again, im extremely impressed by your elaborate answer, thank you! If i ever meet you, i owe you one or three beers :beers:

1 Like

Forum kindly sponsored by