Introduction to the Bash Shell

  1. Overview
  2. Short reference
  3. Redirection, piping, and filters
  4. Writing your own filters
  1. Simple BASH programming
    1. Functions
    2. Conditionals
    3. Iteration
    4. Other constructs
  1. Enhancing your BASH experience

Overview

A very popular shellshell for Unix and Linux is called bashbash, which is kind of short for Bourne-again shell, as it was a replacement for an early shell called the BourneBourne shell, written by Stephen Bourne. It is the default shell for the Unix-based MacOS XMacOS X and most LinuxLinux distributionsdistributions. It is an extremely powerful shell. Earlier shells that influenced bash are the Korn shell (ksh)Korn shell (ksh), the C shell (csh)C shell (csh), and the improved C shell (tcsh)improved C shell (tcsh). Shells abound in the Unix-based world. Bash comes with a powerful programming language built-in. It resembles C to some degree.

Short Reference

online man pages

The first place to get information on any external command (program) used in bash is to use the switch --help on the program:

user@host:~> program --help
This gives a short synopsis of what the program does and how some of the major command line switches can be used. To get the full help for a program, you would consult the man pagesman pages. The simplest way is to type:
user@host:~> man program
You may need to specify the section if there are ambiguities:
man 1 mkdir
man 2 mkdir
man 1 printf
man 3 printf
Sections of the man pages:
1   Executable programs or shell commands
2   System calls (functions provided by the kernel)
3   Library calls (functions within program libraries)
4   Special files (usually found in /dev)
5   File formats and conventions eg /etc/passwd
6   Games
7   Miscellaneous (including macro packages and conventions), e.g. man(7), groff(7)
8   System administration commands (usually only for root)
9   Kernel routines [Non standard]
You can use the -k option (equivalent to the apropos command) to get a list of related topics, for example:
man -k mkdir
Displays:
mkdir (1)            - make directories
mkdir (2)            - create a directory
mkdirat (2)          - create a directory relative to a directory file descriptor
These two techniques (man and --help) will only work on external commands, i.e. programs. To get help on built-in commands, use the help command:
help <built-in command>
Some examples:
help cd
help type
help help
To discover whether or not a command is a built-in command or external command, use the type built-in command:
$ type cd
$ cd is a shell builtin
$ type diff
$ diff is /usr/bin/diff
$ type ls
$ ls is aliased to `ls --color=auto'
$ type dir
$ dir is aliased to `ls -l --color --group-directories-first'
$ type foo
$ bash: type: foo: not found
$ type sudo
$ sudo is hashed (/usr/bin/sudo)
Commands are hashed for increased performance. See the hash command for details.

The shaded commands are external commands. All others are internal, although some can be both.

bash CommandSimilar
Windows Command
Description
chmod attrib.exe Change a file's mode (attributes)
cat type Display a text file (also concatenates files)
cd cd Change directory
clear cls Clears the screen
cp copy Copy files
date date/time Read/set the system date and time
echo* echo Print to the screen
for for Looping construct
if if Conditional construct
less more.com Display one page of text at a time.
ls dir List files
man help.exe Displays the man (manual) page for a given command
mkdir mkdir/md Create (make) a new directory
mv move/rename Move and/or rename files
popd popd Pop most recent directory and change to it
pushd pushd Save current directory and change
rm del Removes (deletes) a file
rmdir rmdir/rd Removes (deletes) a directory
A brief list of other useful commands and programs:
CommandDescription
alias Create an alias (shortcut) for a command
cal Display a calendar to the screen (text)
chown Change owner and group of a file
dd Data dump, raw read/write for files and devices
diff Display differences between files
du Calculate disk usage
file Determine a files type
find Search for files matching certain criteria
grep Search files for lines matching specified text
head Display first few lines in a file
history Display command history
kill* Send a signal to a process
ln Create a link between files
ps List processes and status
pwd* Print current working directory
tail Show last few lines of a file
time* Measure the running time of a program (External command as well)
type Determine the type of a command (e.g. file, alias, keyword, built-in, etc.)
wc Prints count of lines, words, and bytes
which Shows where a program is in the file system
*These commands also have external equivalents that are used by other shells (e.g. csh)

To create a PDF from the man pages, use this command (showing chmod as an example):

man -t chmod > chmod.ps && ps2pdf chmod.ps && rm chmod.ps
For easier use, create a script called man2pdf.sh and put this text in it:
#!/bin/bash

if [[ $# -eq 0 ]]; then
  echo "Usage: man2pdf topic"
  exit
fi

man -t $1 > $1.ps && ps2pdf $1.ps && rm $1.ps
Make sure the script is executable and in your path somewhere (e.g. ~/bin):
chmod +x man2pdf.sh

Redirection, Piping and Filters (Review)

This is where the real power of the command line lies. It is simply impossible (or, at the very least, tremendously difficult) to do these things using a graphical user interface (GUI). There is a wealth of information about this on the Internet.

Recall from CS 120:

Here's a couple of very simple examples that show how filters work. We'll use this file: Declaration of Independence without word-wrap. There are actually 9 lines in the file, and 4 of them are empty.

Examples showing commands, redirection, piping, switches, arguments. The cut command is very powerful.
    If we break it down one pipe at a time, we will see how this all works.

  1. First, we extract only the lines that contain the string IP Address using the grep filter:
    $ cat ip.txt | grep "IP Address"
    
    The output is (there are 8 leading spaces, shown with dots ········ to the left):
    ········IP Address. . . . . . . . . . . . : 192.168.17.1
    ········IP Address. . . . . . . . . . . . : 192.168.13.1
    ········IP Address. . . . . . . . . . . . : 10.10.32.67
    ········IP Address. . . . . . . . . . . . : 192.168.56.1
    
  2. Next, we extract only the characters from position 45 until the end of the line, using the cut filter:
    $ cat ip.txt | grep "IP Address" | cut -c 45-
    
    The output is:
    192.168.17.1
    192.168.13.1
    10.10.32.67
    192.168.56.1
    
  3. Then, we extract the first 2 fields of the string using cut again, specifying the period as the field delimiter:
    $ cat ip.txt | grep "IP Address" | cut -c 45- | cut -d. -f1,2 
    
    The output is:
    192.168
    192.168
    10.10
    192.168
    
  4. Now, sort the output using the sort filter:
    $ cat ip.txt | grep "IP Address" | cut -c 45- | cut -d. -f1,2 | sort 
    
    The output is:
    10.10
    192.168
    192.168
    192.168
    
  5. To remove duplicates, we use the uniq filter (input must be sorted, hence the previous step):
    $ cat ip.txt | grep "IP Address" | cut -c 45- | cut -d. -f1,2 | sort | uniq
    
    The output is:
    10.10
    192.168
    
  6. Finally, we send the output to the wc filter (word count) specifying we just want the line count:
    $ cat ip.txt | grep "IP Address" | cut -c 45- | cut -d. -f1,2 | sort | uniq | wc -l
    
    The output is:
    2
    
    All of the filters are configurable via command line options:

    By the way, the script above to create PDF documents from the man pages could have been done using pipes:

    man -t grep | ps2pdf - > grep.pdf
    

    And that, boys and girls, is what makes the command line indispensible for the experienced user. Imagine if you had to write a C/C++ program to do this; it would be quite lengthy. (It's not just the parsing, but you'd have to figure out a system-independent way to query the system for IP addresses, etc.)

One of the best things you can do as a student learning the power of computers is to learn the filters in /usr/bin. There are hundreds and learning all of them is unlikely. However, you only really need to learn a couple of dozen to make your computing significantly more productive.

Over time, you will find yourself spending more and more time at the command line because it enables you to do things that are impossible in a GUI. Also, before you sit down to write a program in C or C++ to do some kind of system work, find out if there is a program or set of filters that will do what you want. Most likely, there is, or at least you may only need to write another filter to complete the task.

Writing Your Own Filters

Here is some simple pseudocode to implement a filter similar to the nl filter (number lines), which adds line numbers to output:
FILE *infile

initialize counters;

IF filename given on command line
  infile = open file for read/text
  (Handle errors)
ELSE
  infile = stdin;
END IF
  
WHILE not end of file
  read a character
  inc char_counter
  IF this is the first char read or the previous character is a newline
    print line number
    inc line_counter
  END IF
  print the character that was read
  set prev char to character read
END WHILE

IF not reading from stdin
  close file
END IF

Simple bash Programming

Bash supports:


Variables in bash:

Bash scripts: As with any programming language, iteration (looping), conditionals (flow control, if/then...), and functions are really important and bash supports all of them very well.


Arithmetic operations

  • Arithmetic in bash seems a little strange at first. Examples will illustrate.
  • Example 1 - Using the let command.
  • CodeOutputDescription
    a=1+2
    echo $a
    
    let a=1+2
    echo $a
    
    let a = 1 + 2
    echo $a 
    
    let a="1 + 2"
    echo $a
    
    
    1+2
    
    
    3 
    
    error
    
    
    
    3
    
    No arithmetic done. Verbatim assignment.


    The let command is for arithmetic.


    Can't have any spaces with let.


    Using quotes allows spaces.

  • Example 2 - Using (( )) for arithmetic context.
  • CodeOutputDescription
    a=1
    
    ((a=$a+2))         
    echo $a
    
    ((a = a + 2))      
    echo $a
    
    ((a += 2))         
    echo $a
    
    
    
    
    3
    
    
    5 
    
    
    7
    
    Set a to 1

    Add 2 to a


    Same, but can use spaces and no $.


    Same.


    Functions


    Conditionals

    Note:

    What's the deal with the single and the double brackets? ([ ] vs. [[ ]]). The best answer I've found on the subject is here.

    In a nutshell, [ ] is older and more portable, while [[ ]] is newer, easier to use, but doesn't work with all shells. Since we are talking about the bash shell, this will always work. By the way, there is actually a program in /usr/bin that is named [. That's right, do this:

    ls -l /usr/bin/[
    
    and you will see something like this:
    -rwxr-xr-x 1 root root 30,244 2011-02-23 05:22 /usr/bin/[
    


    Iteration

  • There are for loops and while loops of course.
  • Block-style for loop (CS 180 style):
  • for arg in LIST
    do 
      command(s)... 
    done
    
  • One line needs semicolons:
  • for arg in LIST; do command(s)...; done
    
  • Example 1 - These all do the same thing
  • 1234
    for a in 1 2 3 4 5
    do
      echo -n "$a "
    done  
    
    NUMS="1 2 3 4 5"
    for a in $NUMS
    do
      echo -n "$a "
    done  
    
    for a in {1..5}
    do
      echo -n "$a "
    done  
    
    for ((a = 1; a <= 5; a++))
    do
      echo -n "$a "
    done
    

    Output:

    1 2 3 4 5 
    
    Note that these two lines mean different things:
    for a in 1 2 3 4 5
    
    for a in "1 2 3 4 5"
    
    The first contains 5 separate items (numbers), but the second is a single item (a string). Notice in the second example above, the string "1 2 3 4 5" is assigned to a variable, NUMS, and that variable is used in the for loop.

  • Example 2 - This lists all of the .cpp files in the current directory
  • for a in *.cpp
    do
      echo "$a "
    done  
    
  • Example 3 - Calling a function in the for loop
  • generate_list()
    {
      echo "one two three"
    }
    
    for word in $(generate_list)
    do
      echo "$word"
    done
    
  • Block-style while loop (CS 180 style):
  • while CONTROL-COMMAND
    do 
      COMMAND(S)... 
    done
    
  • One line needs semicolons:
  • while CONTROL-COMMAND; do COMMAND(S)...; done   
    
    
  • Example 4 - Block-style while loop example
  • i=0
    while [ $i -lt 4 ]
    do
      i=$(($i + 1))   # can also use ((i++))
      echo -n "$i "
    done
    
  • Example 5 - Calling a function in the while loop
  • t=0
    condition()
    {
      ((t++))
    
      if [ $t -lt 5 ]
      then
        return 0  # true
      else
        return 1  # false
      fi
    }
    
    while condition
    do
      echo "Still going: t = $t"
    done
    
  • Other useful tidbits

  • bash_script used to produce all of the examples. It ain't pretty, but here it is. There are actually some lines in the script that aren't on this web page. Examples of looping over filenames in a directory.

    This is an excellent place to start: Bash Guide for Beginners

    A real world example that I use on student submissions.

    Enhancing Your bash Experience

    Bash is infinitely customizable. You can do things such as: An important file used to customize your bash shell is a hidden file in your home directory. This file is a startup script called .bashrc.bashrc and it's a simple text file. (The dot . hides the file from the ls program.) I'm going to give you some useful customizations to put in your .bashrc file.

    Aliases

    To create aliases, use this format in your startup script:
    alias short_name='some_other_command'
    
    Here are some common ones Windows users like to create:
    alias dir='ls -l'
    alias del='rm'
    alias cp='cp --preserve=timestamps'
    

    Example using the ls (list files) command:

    Default ls command:

    mmead@olga:~/digipen/cs180> ls 
    BatchFiles.html                ding.wav      quiz_material
    Hotel California.mp3           dumpit.exe    quiz_material.zip
    OperatingSystemConcepts8e.zip  exams         sandbox
    bash.odt                       foo.mmg       spanish.txt
    batch                          graph-0.jpg   start.wav
    batch.odt                      graph-1.jpg   temp.html
    book                           makehelp.bat
    didcgaf-setup.txt              new.css
    


    ls using long listing (lowercase 'L': -l), and listing directories before files (--group-directories-first):

    mmead@olga:~/digipen/cs180> ls -l --group-directories-first
    total 145,592,320
    drwxr-xr-x  3 mmead mmead       4,096 2011-05-16 08:36 batch
    drwxr-xr-x 12 mmead mmead       4,096 2011-05-09 20:52 book
    drwxr-xr-x  2 mmead mmead       4,096 2011-05-18 19:29 exams
    drwxr-xr-x  2 mmead mmead       4,096 2011-05-09 21:11 quiz_material
    drwxr-xr-x  2 mmead mmead       4,096 2011-05-12 11:45 sandbox
    -rw-r--r--  1 mmead mmead      14,188 2011-05-18 19:25 bash.odt
    -rw-r--r--  1 mmead mmead      56,690 2011-05-15 20:39 BatchFiles.html
    -rw-r--r--  1 mmead mmead      30,568 2011-05-15 11:52 batch.odt
    -rw-------  1 mmead mmead       3,480 2010-10-10 22:09 didcgaf-setup.txt
    -rwxr-xr-x  1 mmead mmead      80,856 2001-08-23 05:00 ding.wav
    -rw-r--r--  1 mmead mmead      58,880 2011-05-10 20:19 dumpit.exe
    -rw-r--r--  1 mmead mmead           0 2011-05-18 19:20 foo.mmg
    -rw-r--r--  1 mmead mmead      25,932 2010-03-30 11:49 graph-0.jpg
    -rw-r--r--  1 mmead mmead      25,679 2010-03-30 11:52 graph-1.jpg
    -rw-------  1 mmead mmead   6,533,037 2010-10-31 17:22 Hotel California.mp3
    -rw-r--r--  1 mmead mmead       4,291 2011-05-16 08:34 makehelp.bat
    -rw-------  1 mmead mmead      11,140 2011-04-20 12:58 new.css
    -rw-r--r--  1 mmead mmead 138,465,681 2011-05-09 20:53 OperatingSystemConcepts8e.zip
    -rw-r--r--  1 mmead mmead      52,876 2011-05-06 18:30 quiz_material.zip
    -rw-r--r--  1 mmead mmead         153 2010-10-16 10:57 spanish.txt
    -rwxr-xr-x  1 mmead mmead       1,192 2001-08-23 05:00 start.wav
    -rw-r--r--  1 mmead mmead       1,253 2011-05-18 19:33 temp.html
    

    Same as above but enabling color output (--color):

    mmead@olga:~/digipen/cs180> ls -l --group-directories-first --color=auto
    total 145,592,320
    drwxr-xr-x  3 mmead mmead       4,096 2011-05-16 08:36 batch
    drwxr-xr-x 12 mmead mmead       4,096 2011-05-09 20:52 book
    drwxr-xr-x  2 mmead mmead       4,096 2011-05-18 19:29 exams
    drwxr-xr-x  2 mmead mmead       4,096 2011-05-09 21:11 quiz_material
    drwxr-xr-x  2 mmead mmead       4,096 2011-05-12 11:45 sandbox
    -rw-r--r--  1 mmead mmead      14,188 2011-05-18 19:25 bash.odt
    -rw-r--r--  1 mmead mmead      56,690 2011-05-15 20:39 BatchFiles.html
    -rw-r--r--  1 mmead mmead      30,568 2011-05-15 11:52 batch.odt
    -rw-------  1 mmead mmead       3,480 2010-10-10 22:09 didcgaf-setup.txt
    -rwxr-xr-x  1 mmead mmead      80,856 2001-08-23 05:00 ding.wav
    -rw-r--r--  1 mmead mmead      58,880 2011-05-10 20:19 dumpit.exe
    -rw-r--r--  1 mmead mmead           0 2011-05-18 19:20 foo.mmg
    -rw-r--r--  1 mmead mmead      25,932 2010-03-30 11:49 graph-0.jpg
    -rw-r--r--  1 mmead mmead      25,679 2010-03-30 11:52 graph-1.jpg
    -rw-------  1 mmead mmead   6,533,037 2010-10-31 17:22 Hotel California.mp3
    -rw-r--r--  1 mmead mmead       4,291 2011-05-16 08:34 makehelp.bat
    -rw-------  1 mmead mmead      11,140 2011-04-20 12:58 new.css
    -rw-r--r--  1 mmead mmead 138,465,681 2011-05-09 20:53 OperatingSystemConcepts8e.zip
    -rw-r--r--  1 mmead mmead      52,876 2011-05-06 18:30 quiz_material.zip
    -rw-r--r--  1 mmead mmead         153 2010-10-16 10:57 spanish.txt
    -rwxr-xr-x  1 mmead mmead       1,192 2001-08-23 05:00 start.wav
    -rw-r--r--  1 mmead mmead       1,253 2011-05-18 19:33 temp.html
    
    Creating an alias for the above command in your .bashrc file:
    alias dir='ls -l --color --group-directories-first'
    
    Now you can simply type dir to get the above output. Oh, and to get all of your numbers to have those nice commas in them, add this line to your startup script:
    export BLOCK_SIZE=\'1
    


    Changing the Command Prompt

    You'll notice that in the examples above, my command prompt was colored yellow. There are a couple of very good reasons for this.
    1. First, by coloring the prompt, it is easy to find the commands in a sea of output. If all output is the same color as the prompt, it's very difficult to find the command.
    2. Second, by using a different color prompt between "user" mode and "superuser" mode, it makes it less likely that you'll do something bad to your computer. (This isn't a cure for that and I'm not going to get into the whole philosophy of "when and why you should ever be root (administrator) while using the command line")
    3. Most bash shells do automatic coloring today, but even a few years ago this wasn't done. That's why I did this. You may find that this is unecessary today. But, you still may want to change the colors to something you prefer.

      This is how you would do it:

    export PS1="\[\033[1;33m\]\u@\h:\w>\[\033[0m\]"
    
    The highlighted portion is what's interesting. The '1' means bold and the '33' means yellow. Now, the prompt will be bold yellow on black (the default background color). You could add a third number, say, '44' (1;33;44)which means a blue background. The prompt is now hard-coded to be yellow. However, I want the prompt to change based on what role I'm playing (normal user or root). I want yellow for a normal user and red for root. I'm going to write a function that will determine that and set the correct color based on that.
    # Assume that my user ID is 1234
    # 33=yellow, 31=red, admin/root/superuser is 0
    user_color()
    {
      if [ "$UID" -eq "0" ]; then
        echo 31
      elif [ "$UID" -eq "1234" ]; then
        echo 33
      fi
    }
    
    Then, change the prompt to call the function:

    export PS1="\[\033[\$(user_color)m\]\u@\h:\w>\[\033[0m\]" 
    
    Consult this page to learn about all of the characters used above.
    dircolors Abbreviations
    fi = normal file
    di = directory
    ln = symbolic link
    pi = fifo pipe
    so = socket
    bd = block device
    cd = character device
    or = symbolic link to nonexistent file (orphan)
    mi = symbolic link pointing to non-existent file
    ex = executable
    

    Color CodesColor Codes (cont.)
     00 = normal
     01 = bold
     04 = underlined
     05 = blinking
     07 = reversed
     08 = concealed
     31 = red
     32 = green
     33 = orange
     34 = blue
     35 = purple
     36 = cyan
     37 = grey
     40 = black background
     41 = red background
     42 = green background
     43 = orange background
     44 = blue background
     45 = purple background
     46 = cyan background
     47 = grey background
    
     90 = dark grey
     91 = light red
     92 = light green
     93 = yellow
     94 = light blue
     95 = light purple
     96 = turquoise
    100 = dark grey background
    101 = light red background
    102 = light green background
    103 = yellow background
    104 = light blue background
    105 = light purple background
    106 = turquoise background
    

    See the man pages for dircolors and dir_colors


    Colorize the Output from grep

    Add these lines to your startup script:
    # Add color to grep
    export GREP_COLOR="44;37;01"
    export GREP_OPTIONS="--color=auto"
    
    The power of grep:
    $ grep -i "^a.*b.*c.*d.*" /usr/share/dict/american-english  
    
    abdicated
    abducted
    abracadabra
    abracadabra's
    abscessed
    abscond
    absconded
    absconding
    absconds
    abstracted
    abstractedly
    
    $ grep -i "^b.*s.*g.*d.*" /usr/share/dict/american-english  
    
    besieged
    


    Colorizing man Pages

    Add these lines to your startup script:
    # Add color to man pages
    export LESS_TERMCAP_mb=$'\E[01;31m'      # begin blinking
    export LESS_TERMCAP_md=$'\E[01;34m'      # begin bold
    export LESS_TERMCAP_me=$'\E[0m'          # end mode
    export LESS_TERMCAP_se=$'\E[0m'          # end standout-mode
    export LESS_TERMCAP_so=$'\E[01;44;33m'   # begin standout-mode - info box
    export LESS_TERMCAP_ue=$'\E[0m'          # end underline
    export LESS_TERMCAP_us=$'\E[01;32m'      # begin underline
    


    The bash shell has all of the modern shell features you would want.

    Tab Completion

    This will auto-complete the command you are typing. But, in addition to completing the names of files, it can complete many other things. Most notably, it can complete names of commands and programs. For example, there is a program in most Linux distributions called whereis, which is used to locate the binary, source, and manual page files for a command. If you type
    whereis chmod
    
    You'll see something like this:
    chmod: /bin/chmod /usr/share/man/man1/chmod.1.gz /usr/share/man/man2/chmod.2.gz
    
    However, if you just type whe and then press TAB (<TAB> is the Tab key)
    whe<TAB>
    
    it will complete it to this:
    whereis
    
    This is especially useful if the filenames or commands are very long. Not only does it save lots of typing, but you can't make a typo! (Read It! Learn It! Live it!)

    If there is more than one command or file that will complete what you've typed, bash won't complete it because it's ambiguous. In this case, pressing the TAB key twice quickly, will show you a list of possible candidates. For example, typing this

    wh<TAB><TAB>
    
    will show something like this (depending on what packages you have installed):
    whatis    whereis   which     while     whiptail  who       whoami    whois
    
    You must provide additional characters so the completion is no longer ambiguous.

    Cycling Through the Command Completion

    Personally, I don't like the default behavior of TAB completion, especially for filenames. It may require pressing the TAB key 3 times: once to indicate that there is no completion, or worse, it indicates an ambiguity (and still does nothing). Then, you must press it 2 more times to show a list. Finally, you must disambiguate the completion with more characters. Fortunately, the designers saw the flaw in this interface and gave us an alternative.

    The alternative is to have the TAB key cycle through the choices. So, in the example above, typing TAB will first show whatis and pressing TAB a second time will show whereis. Pressing TAB will cycle through the choices. This is especially useful if the first several characters in a filename match (which is common). Suppose you had these two filenames in a directory:

    filename-a.txt
    filename-b.txt
    
    With the default method, you would have to type: filename-a<TAB> or filename-b<TAB> to complete it, which is useless. With the cycling method, pressing TAB once gives filename-a.txt and pressing it a second time gives filename-b.txt. Perfect!

    To enable this cycling method, add this to your .bashrc file:

    bind '"\t":menu-complete'
    

    Navigating and Search Through the Command History

    Like most modern shells, bash keeps a history of all of the commands that you type. You can navigate through this history by pressing the up (previous) and down (next) arrow keys. This works great if the command you want to repeat was typed in recently. But, suppose you want to repeat a long command and since you've typed that command, you typed another 50 commands. You would have to press the up arrow 50 times to reach it!

    In this case, you want to search for that command. Let's say you ran this command 20 minutes ago:

    valgrind -q --leak-check=full --show-reachable=yes --tool=memcheck ./memmgr 1 2
    
    You wouldn't want to type that again, and it may be very far back in your command history. To search, type Ctrl-r (Control and lowercase R). You'll see this:
    (reverse-i-search)`': 
    
    Now, as you type characters, whatever previous command matches will be shown. If the only command you've typed since that long command starts with the lowercase letter 'V', then it will complete it as soon as you press 'v'. The best way to see how this works is to try it. Warning, once you've used it, you will not be able to live without it! Also, depending on your history settings, you might be able to not only call up commands you typed 20 minutes, but commands you typed 20 weeks ago or 20 months ago or longer!

    But there's more! You don't have to type the first characters in the command. If you've used the valgrind command with dozens of different options, you'd have to cycle through all of them to find the one you want. If you pick something a little unique within the command line, it will jump to that one. For example, typing Ctrl-r and then the characters t o o will match the --tool=memcheck portion and show the entire command with that substring it it. Very, very cool!

    Case-insensitive command completion

    Anyone who has worked in the bash shell (or most any shell, for that matter) knows that command/filename completion is one of the most powerful features of the shell. Most of the time, I try to use all lowercase characters in my filenames. However, sometimes there are uppercase characters as well. By default, filename completion is case-sensitive. This means that if I have a directory named Downloads and I type this:
    ls d<TAB>
    
    it will not complete the command. If it does, it's not completing it with what I want, which is this:
    ls Downloads
    
    If you want the completion to ignore the case of the characters (case-insensitive) then you have to configure your environment for that. However, the configuration doesn't go into your .bashrc, it goes into your .inputrc file. It's likely that you don't have a .inputrc in your home directory, so you'll have to create one with any text editor. In your .inputrc file, simply place this one line at the top:
    set completion-ignore-case on
    
    Now, when you open up a new bash shell, the completions will be case-insensitive.


    Making the Changes Permanent

    In your home directory, you may have file named .bashrc that is hidden. The dot/period is what makes it hidden. This file is read every time you open a terminal window. By placing the commands in this file, you will always have the functionality. You can place all of your personal modifications in this file.

    If the file exists, just open it with a text editor and add the lines at the bottom. If the file doesn't exist, it will be created. gedit is a decent text editor for new Linux users:

    gedit ~/.bashrc
    
    Add these lines to the file:
    # Now, the dir command will display files properly :)
    alias dir='ls -l --color --group-directories-first'
    
    # Add color to grep output
    export GREP_COLOR="44;37;01"
    export GREP_OPTIONS="--color=auto"
    
    # Add color to man pages
    export LESS_TERMCAP_mb=$'\E[01;31m'      # begin blinking
    export LESS_TERMCAP_md=$'\E[01;34m'      # begin bold
    export LESS_TERMCAP_me=$'\E[0m'          # end mode
    export LESS_TERMCAP_se=$'\E[0m'          # end standout-mode
    export LESS_TERMCAP_so=$'\E[01;44;33m'   # begin standout-mode - info box
    export LESS_TERMCAP_ue=$'\E[0m'          # end underline
    export LESS_TERMCAP_us=$'\E[01;32m'      # begin underline
    
    # This causes the TAB-completion to cycle through possible matches
    bind '"\t":menu-complete'
    
    # This causes commas to be inserted in numbers, e.g. 1234567890 becomes 1,234,567,890
    export BLOCK_SIZE=\'1
    
    You can add as much stuff as you want to the file.

    Note: Simply modifying the .bashrc in your home directory will not cause the changes to take effect. If you want them to take effect immediately, you have to type this while in your home directory:

          source .bashrc

    Now the changes are in effect only for the current shell. If you have other shells already open, you will have to type that command in each one. However, any new shells that you open up will have the changes.


    Creating functions

    If you have more than one line of code, it may be more convenient to create a function instead of an alias. This example shows a function that contains 3 lines:
    lpath()
    {
      perl -e 'print "\n";
      print join("\n", split(/:/, $ENV{'PATH'}));
      print "\n";'
    }
    
    Typing:
    lpath
    
    at the command prompt will display all of the paths in the PATH environment variable, each on its own line. Of course, there's a bazillion ways to do the same thing, and this is almost as short as it gets:
    echo $PATH | tr : '\n'
    
    It uses the tr filter (translate) to replace each colon with a newline. Nice.

    This example is more verbose. It will extract (unzip, untar, uncompress, etc.) a file based on the file's extension.

    #------------------------------------------
    #------Extraction of compressed files------
    # from ARCH Wiki
    
    extract() 
    {
      if [ -f $1 ]; then
        case $1 in
            *.tar.bz2)   tar xvjf $1    ;;
            *.tar.gz)    tar xvzf $1    ;;
            *.bz2)       bunzip2 $1     ;;
            *.rar)       rar x $1       ;;
            *.gz)        gunzip $1      ;;
            *.tar)       tar xvf $1     ;;
            *.tbz2)      tar xvjf $1    ;;
            *.tgz)       tar xvzf $1    ;;
            *.zip)       unzip $1       ;;
            *.Z)         uncompress $1  ;;
            *.7z)        7z x $1        ;;
            *)           echo "don't know how to extract '$1'..." ;;
        esac
      else
        echo "'$1' is not a valid file!"
      fi
    }
    


    Global customization

    Suppose you want every user on the system to enjoy these modifications? If so, you can edit /etc/bash.bashrc to include them. (Go look at that file.) This is the system-wide startup file. You will have to use sudo to edit it because it is a system file. Also, in Real Life you wouldn't necessarily force every user to have to use your settings. However, the local .bashrc file overrides the system one, so the users can set things up however they want. On my own Linux systems, I put a few things in the system bash.bashrc because I want them to be available when I'm masquerading around the system as root or some other user. Just as with .bashrc, there is a system-wide file also in /etc named inputrc (no leading dot) that is for all users on the system. So, if you want all of the users to have the settings in that file as well, you would edit that file instead.

    Other useful links: