An Explanation of .bashrc and .bash_profile

An Explanation of .bashrc and .bash_profile

Both the ~/.bashrc and ~/.bash_profile are scripts that might be executed when bash is invoked. The ~/.bashrc file gets executed when you run bash using an interactive shell that is not a login shell. The ~/.bash_profile only gets executed during a login shell. What does this all mean? The paragraphs below explains interactive shells, login shells, .bashrc, .bash_profile and other bash scripts that are executed during login.

Login Shells (.bash_profile)

A login shell is a bash shell that is started with – or –login. The following are examples that will invoke a login shell.

sudo su -
bash --login
ssh user@host

When BASH is invoked as a login shell, the following files are executed in the displayed order.

/etc/profile
~/.bash_profile
~/.bash_login
~/.profile
Although ~/.bashrc is not listed here, most default ~/.bash_profile scripts run ~/.bashrc.

Purely Interactive Shells (.bashrc)

Interactive shells are those not invoked with -c and whose standard input and output are connected to a terminal. Interactive shells do not need to be login shells. Here are some examples that will evoke an interactive shell that is not a login shell.

sudo su
bash
ssh user@host /path/to/command

In this case of an interactive but non-login shell, only ~/.bashrc is executed. In most cases, the default ~/.bashrc script executes the system’s /etc/bashrc.

Be warned that you should never echo output to the screen in a ~/.bashrc file. Otherwise, commands like ‘ssh user@host /path/to/command’ will echo output unrelated to the command called.

Non-interactive shells

Non-interactive shells do not automatically execute any scripts like ~/.bashrc or ~/.bash_profile. Here are some examples of non-interactive shells.

su user -c /path/to/command
bash -c /path/to/command

Bash File Loops

Some examples of iterating through files and looping through file content in Bash. For details, see the Bash man page or the Bash reference manual.

Loop Through Files


for FILE in *; do
  # do something with $FILE
  echo "File: $FILE"
done

For more control, use /usr/bin/file


for FILE in $(find ./ -name *.html -type f); do
  # do something with $FILE
  echo "HTML File: $FILE"
done

Loop Through Lines in a File


while read LINE; do
  # do something with $LINE
  echo "Line: $LINE"
done < /etc/hosts

Loop Through Words in a File


for WORD in $(cat /etc/hosts); do
  # do something with $WORD
  echo "Word: $WORD"
done

Loop Through Characters in a File


while read -n1 CHAR; do
  # do something with $CHAR
  echo "Character: $CHAR"
done < /etc/hosts

Bash Trap Control C

Do you want to catch control-c keyboard interrupts in your Bash program? Use the Bash builtin trap command to catch system signals. The following runs control_c() when a user interrupts the main() section with a Control-C (SIGINT).


#!/bin/bash
 
cleanup()
# example cleanup function
{
  rm -f /tmp/tempfile
  return $?
}
 
control_c()
# run if user hits control-c
{
  echo -en "\n*** Ouch! Exiting ***\n"
  cleanup
  exit $?
}
 
# trap keyboard interrupt (control-c)
trap control_c SIGINT
 
# main() loop
while true; do read x; done

Bash & (Ampersand)

The Bash & (ampersand) is a builtin control operator used to fork processes. From the Bash man page, “If a command is terminated by the control operator &, the shell executes the command in the background in a subshell”.

If logged into an interactive shell, the process is assigned a job number and the child PID is displayed. The job number below is one.


bash$ sleep 30 &
[1] 3586

Note that when a process is forked, the child PID is stored in the special variable $!


bash$ echo $!
3586

You can terminate the job by its job number like so:


bash$ jobs
[1]+ Running sleep 30 &
bash$ kill %1
[1]+ Terminated sleep 30
bash$

Bash Calculator

For floating point math calculations in Bash, use /usr/bin/bc.
A simple calculator program might look something like this:


#!/bin/bash
echo "scale=2; $@" | /usr/bin/bc -l
exit $?

Alternatively, a calculator function:


calc()
{
   echo "scale=2; $@" | /usr/bin/bc -l
   return $?
}

If you are looking for more, here are other ways to do math in Bash.

Bash Functions

Here are some example BASH functions. For more information, see the online BASH Function documentation.

Declaring Functions

A BASH function must first be declared. One of the two methods can be used to declare a BASH function:

Method #1: function name compound-command

function say_goodbye {
    echo "goodbye"
}

Method #2: name() compound-command

say_hello() {
    echo "hello"
}

Using Functions

Just call the name as you would any other simple command:

say_hello
hello

Passing Variables

Pass variables into the function by space delimited fields and accept parameters using $1, $2 and so on.

my_function() {
    echo "$1"
}

Example:

my_function hello this is a test
hello

To expand all variable parameters inside the function, use $@

log() {
    echo "[$(date)]: $@"
}
log this is a test
[Sun Jun 22 10:21:26 PDT 2008]: this is a test

Return Codes

Functions return an exit status to their caller:

subtest() {
return 1
}

The function will return 1:

subtest || echo "Returned: $?"
Returned: 1

Since the function returned 1, it failed the test of || (or).

Bash For Loop

Below are examples of the Bash for loop in action. If you need more help, see the official Bash documentation for an introduction to Bash programming.

Examples

Echo all jpg files in the current folder:

for JPG in *.jpg; do 
    echo $JPG
done

Count a list of numbers:

for NUM in $(seq 1 10); do
    echo $NUM
done

One liners work as well:

for n in $(seq 3); do echo $n; done

Iterate through the process ID’s for httpd and kill them:

for PID in $(ps -C httpd | awk '/httpd/ { print $1 }'); do
    kill -TERM $PID
done

List arguments to a function named showarg:

showarg() {
    for ARG in $@; do
        echo $ARG
    done
}

Loop through folders and back them up using tar:


DATE=$(date +'%Y-%m-%d')
for DIR in /etc /var /root; do
    tar -czvf /backups/$DIR_$DATE.tgz $DIR
done

Bash Arrays

Arrays in Bash are quite simple. Here are some array examples to get you going. The official Bash documentation has more details and examples.

Initialize an entire array:

bash$ DAYS=(mon tue wed thu fri sat sun)

There are two ways to reference an entire array:

bash$ echo ${DAYS[@]}
mon tue wed thu fri sat sun
bash$ echo ${DAYS[*]}
mon tue wed thu fri sat sun

Initialize array element

bash$ ARRAY[0]="Fedora"
bash$ ARRAY[1]="RedHat"
bash$ ARRAY[2]="CentOS"

Display an element

bash$ echo ${ARRAY[0]}
Fedora

Get the length of an array:

bash$ echo ${#ARRAY[@]}
3

Get the length of an array value based on index:

bash$ echo ${ARRAY[0]} 
Fedora
bash$ echo ${#ARRAY[0]} 
6

Get the subset of an array through trailing substring extraction:

bash$ echo ${ARRAY[@]:0} 
Fedora RedHat CentOS
bash$ echo ${ARRAY[@]:1} 
RedHat CentOS
bash$ echo ${ARRAY[@]:2} 
CentOS

Argument List Too Long

Getting an “Argument list too long” error using Linux?

This is because you are passing too many arguments to an executable.
For example, using *.html below results in too many arguments to /bin/rm:

rm *.html
bash: /bin/rm: Argument list too long

One solution is to use Bash control loops to iterate through arguments.

for HTMLFILE in *.html
> do
> rm -f $HTMLFILE
> done

Alternatively, the find command can be used to manipulate large data sets.
The following find command is identical in result to the for loop shown above.

bash$ find ./ -maxdepth 1 -name '*.html' -exec rm -f {} \;