Bash Cheat Sheet

Getting Help

Read the manual page: bash and more important use the built-in command "help". For example

$ help continue
continue: continue [n]
    Resume for, while, or until loops.
    
    Resumes the next iteration of the enclosing FOR, WHILE or UNTIL loop.
    If N is specified, resumes the Nth enclosing loop.
    
    Exit Status:
    The exit status is 0 unless N is not greater than or equal to 1.
$

Bash File Operators

The complete list of bash 4.2 test operators:

      -a FILE        True if file exists.
      -b FILE        True if file is block special.
      -c FILE        True if file is character special.
      -d FILE        True if file is a directory.
      -e FILE        True if file exists.
      -f FILE        True if file exists and is a regular file.
      -g FILE        True if file is set-group-id.
      -h FILE        True if file is a symbolic link.
      -L FILE        True if file is a symbolic link.
      -k FILE        True if file has its `sticky' bit set.
      -p FILE        True if file is a named pipe.
      -r FILE        True if file is readable by you.
      -s FILE        True if file exists and is not empty.
      -S FILE        True if file is a socket.
      -t FD          True if FD is opened on a terminal.
      -u FILE        True if the file is set-user-id.
      -w FILE        True if the file is writable by you.
      -x FILE        True if the file is executable by you.
      -O FILE        True if the file is effectively owned by you.
      -G FILE        True if the file is effectively owned by your group.
      -N FILE        True if the file has been modified since it was last read.
    
      FILE1 -nt FILE2  True if file1 is newer than file2 (according to
                       modification date).
    
      FILE1 -ot FILE2  True if file1 is older than file2.
    
      FILE1 -ef FILE2  True if file1 is a hard link to file2.

Bash String Operators

The complete list of bash 4.2 string operators:

      -z STRING      True if string is empty.
    
      -n STRING
         STRING      True if string is not empty.
    
      STRING1 = STRING2
                     True if the strings are equal.
      STRING1 != STRING2
                     True if the strings are not equal.
      STRING1 < STRING2
                     True if STRING1 sorts before STRING2 lexicographically.
      STRING1 > STRING2
                     True if STRING1 sorts after STRING2 lexicographically.

Bash Arrays

Bash has limited support for associative arrays. Note that indexes must be numbers!

# Declaring associative arrays (since Bash v4)
declare -A arr

# Initializing arrays
arr=("string 1", "string 2", "string 3")
arr=([1]="string 1", [2]="string 2", [3]="string 3")

# Assigning values for indexed arrays
arr[4]="string 4"

# Assigning values for associative arrays
arr["my key"]="my value"

# Accessing the array
${arr[@]}         # Returns all indizes and their items (doesn't work with associative arrays)
${arr[*]}         # Returns all items
${!arr[*]}        # Returns all indizes
${#arr[*]}        # Number elements
${#arr[$n]}       # Length of $nth item

# Pushing to array
arr+=("new string value", "another new value")

Bash Regexp Matching

Use conditions with doubled [] and the =~ operator. Ensure not to quote the regular expression. Only BRE are allowed. If the regexp has whitespaces put it in a variable first.

if [[ "$string" =~ ^[0-9]+$ ]]; then 
    echo "Is a number"
fi

Bash Regexp Match Extraction

Variant #1: You can do this with grouping in bash. Despite only BRE being supported grouping works also. Note how you need to set the regexp into a variable because you must not quote it in the if condition!

REGEXP="2013:06:23 ([0-9]+):([0-9]+)"
if [[ "$string" =~ $REGEXP ]]; then
    echo "Hour ${BASH_REMATCH[1]} Minute ${BASH_REMATCH[2]}"
fi

Variant #2: Actually using "expr" can much simpler especially when only on value is to be extracted:

hour=$(expr match "$string" '2013:06:23 \([0-9]\+\)')

Bash - Validate IP

If you need to validate an IP try the following function

function validate_ip {
        local net=$1
        [[ $net =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/[0-9]{1,2}$ ]] || return 1
        [[ ${net#*/} -le 32 ]] || return 1
        local ip=${net%/*}
        local -a oc=(${ip//\./ })
        [[ ${oc[0]} -le 255 && ${oc[1]} -le 255 && ${oc[2]} -le 255 && ${oc[3]} -le 255 ]] || return 1
        return 0
}

Debugging Bash Scripts

For simple tracing add a

set -x

in the script or append the "-x" to the shebang or run the script like this

bash -x <script name>

As "set -x" enables tracing you can disable it with "set +x" again. This allows tracing only a part of the code (e.g. a condition in an inner loop).

Additionally to "-x" you may want to set "-v" to see the shell commands that are executed. Combine both to

set -xv

Writing Safer Scripts

Using

set -e

in a script you ensure that you never forget to check an exit code. Because if you do and the command calls returns an exit code != 0 the script just terminates. Of course you can also use it to not write checks if it is ok to just bail out.

Modifying Bash Command Completion

How to setup your own bash completion schemas. Here is a git example:

complete -W 'add branch checkout clone commit diff grep init log merge mv pull push rebase rm show status tag' git

Note that the above example propably already comes prepared with your Linux distribution. You might want to check default definitions installed in /etc/bash_completion.d for a good starting point.

Bash Simulate Reading From a File

Sometimes you might need to pass a file name when you want to pipe output from a commands. Then you could write to a file first and then used it, but you can also use the ">()" or "<()" operator.

This can be used with all tools that demand a file name paramter:

diff <(echo abc;echo def) <(echo abc;echo abc)

Bash - kill all childs on exit

trap true TERM
kill -- -$$

Bash - History Handling

unset HISTFILE      # Stop logging history in this bash instance
HISTIGNORE="[ ]*"   # Do not log commands with leading spaces
HISTIGNORE="&"      # Do not log a command multiple times

Bash - History with Timestamps

To add timestamps to your history set the following environment variable:

HISTTIMEFORMAT="%Y-%m-%d %H:%M:%S" # Log with timestamps

Apply ulimit Changes Instantly

The problem behind this is documented in this blog post but it boils down to try to use the "-i" switch:

sudo -i -u <user>

If it doesn't work you might need to investigate and change the PAM configuration.

Easier History Navigation

If you do not like Ctrl-R to nagivate the history you can define other keys as PgUp and PgDown in /etc/inputrc:

   "\e[5~": history-search-backward
   "\e[6~": history-search-forward