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:

8 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:

2 Likes

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:

2 Likes

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

I just installed Manjaro Plasma and opened .bashrc to add some aliases, and saw:

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

I'm wondering why there is a mix of double quotes, single quotes, and no quotes, so I was looking for answers and found this thread, which doesn't address this but seems to be a better place to ask than starting a new one.

I thought doubles were required in bash and single in zsh, and all the examples in the wiki have double quotes.

What am I missing?

If the alias is just a reference to a single word, as in the example of "alias more=less", then quotes are not required. In all other cases, they are, but whether they be single or double is not important for aliases.

It is however somewhat of an established practice to use double quotes for all aliases. :wink:

1 Like

Thanks!

1 Like

Double vs single quotes are not relevant in this context, but are if variables are involved: Strings with double quotes are subjected to variable expansion while strings with single quotes are not.
So if you do not want variable expansion: use single quotes.

3 Likes

Cool, didn't know that :slight_smile:

So, to spell it out:

$ myvar="echo Hi!"
$ echo "$myvar" - '$myvar' - "'$myvar'" - '"$myvar"' - "`$myvar`" - '`$myvar`'
echo Hi! - $myvar - 'echo Hi!' - "$myvar" - Hi! - `$myvar`

Just continuing a little by myself down here at the end...

I noticed the alias command lists all aliases using single quotes, and tried it out a little bit.

It may be me just being slow, but I never contemplated this before, and found that with aliases you may not want variable expansion; if the alias uses double quotes then the alias will use the variable value at the time of alias creation, whereas if you use single quotes the alias will contain the variable name and use the variables value at alias execution time:

$ myvar="qwerty"
$ alias test1="echo $myvar"
$ alias test2='echo $myvar'
$ alias | grep test
alias test1='echo qwerty'
alias test2='echo $myvar'
$ test1
qwerty
$ test2
qwerty
$ myvar="123456"
$ test1
qwerty
$ test2
123456

Wether you define the alias in a script or at the command line makes no difference.

1 Like

me, i prefer use functions:

myvar="qwerty"
test3(){
  echo "test3: $1 with myvar: $myvar"
}
test4(){
  value="${1:-HELLO}" # use default value if user no pass parameter
  echo "test4: $value with myvar: $myvar"
}
$ test3
test3:  with myvar: qwerty
$ test4
test4: HELLO with myvar: qwerty
$ test4 Test
test4: Test with myvar: qwerty

no quotes AND i can pass some parameters


for fun; with functions we can override a bash command, for exemple (not usefull)

ls() {
  if [[ -n "$1" && "${1: -1}" == "+" ]]; then
    dest="${1::-1}"
    [ -z "$dest" ] && dest="."
    [ -n ${use_color} ] && pcolor="--color=auto"
    command ls -ld "$dest" $pcolor
    stat -c '%n: at %U:%G %a=%A is %F' "$dest"
  else
    command ls "$@"
  fi
}

ps: use command or absolute path /usr/bin/ or function call this same function...

$ ls Images+
lrwxrwxrwx 1 patrick patrick 25 29 janv.  2019 Images -> /home/Data/Patrick/Images
Images: at patrick:patrick 777=lrwxrwxrwx is lien symbolique

You're right - there is a difference with functions; if you use double quotes you get variable expansion at the time of execution, but with single quotes you get no variable expansion - which is in accordance with what @freggel.doe explained. It's the aliases that's a little bit different; double quotes expand variables at definition time, but single quotes does not expand at definition time and therefore the variable reference is preserved until execution time, at which time it is expanded even if it's in single quotes.

$ myvar="qwerty"
$ cat test.sh 
test3(){
  echo "$myvar"
}
test4(){
  echo '$myvar'
}
$ . test.sh 
$ test3
qwerty
$ test4
$myvar
$ myvar="123456"
$ test3
123456
$ test4
$myvar

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.

Forum kindly sponsored by