The tiny BASH Cheet Sheet provides you (me) with a more or less alphabetically sorted tool-box of the expressions I most commonly use and tend to forget. I will update this cheat sheet now and then depending on more expressions I can’t remember :-)
Args Bash script template Echo Files Functions If IFS Line segmentation Internal variales Numbers Paths Read Shebang Strings Status codes Trap Variable substitution
Args
The variable
$@
is equivalent to$1
$2
… which represent the positional parameters passed to your script. The variable$#
expands to the number of positional parameters in decimal (see also bash(1): GNU Bourne-Again SHell - Linux man page).
Test number of arguments
To test the number of arguments passed to your shell script, you can use the $#
variable:
if [ "$#" -ne 1 ]; then
echo "Illegal number of parameters"
exit 1
fi
This tests whether exactly one argument has been passed.
Evaluate arguments
Given a shell script which supports the arguments -c
or --command
followed by a command, -v
or --verbose
and -h
or --help
:
POSITIONAL_ARGS=()
while [[ $# -gt 0 ]]; do
case $1 in
-h|--help)
printHelp
exit 0
;;
-v|--verbose)
verbose="1"
shift # Skip $1
# shift # Skip $2 if $1 has an argument
;;
-c|--command)
command="$2"
shift # Skip $1
shift # Skip $2 being argument of $1
;;
-*|--*)
echo -e "Unknown argument <${ESC_BOLD}${ESC_FG_RED}$1${ESC_RESET}>!"
exit 1
;;
*)
POSITIONAL_ARGS+=("$1") # Save positional arg
shift # Past argument
;;
esac
done
set -- "${POSITIONAL_ARGS[@]}"
Bash script template
Wrapping up some of the here mentioned cheats, a nifty template for your scripts might look as follows:
#!/bin/bash
[…]
#!/bin/bash
# ------------------------------------------------------------------------------
# INIT:
# ------------------------------------------------------------------------------
CURRENT_PATH="$(pwd)"
SCRIPT_PATH="$(dirname $0)"
cd "${SCRIPT_PATH}"
SCRIPT_PATH="$(pwd)"
cd "${CURRENT_PATH}"
SCRIPT_DIR="${SCRIPT_PATH##*/}"
SCRIPT_NAME="$(basename $0 .sh)"
PARENT_PATH="$(realpath $(dirname $0)/..)"
PARENT_DIR="${PARENT_PATH##*/}"
MODULE_NAME="$(echo -e "${SCRIPT_DIR}" | cut -d- -f3- )"
if [ -z "${MODULE_NAME}" ]; then
MODULE_NAME="$(echo -e "${SCRIPT_DIR}" | cut -d- -f2- )"
if [ -z "${MODULE_NAME}" ]; then
MODULE_NAME="${SCRIPT_DIR}"
fi
fi
if [ -z ${COLUMNS} ] ; then
export COLUMNS=$(tput cols)
fi
# ------------------------------------------------------------------------------
# ANSI ESCAPE CODES:
# ------------------------------------------------------------------------------
ESC_BOLD="\E[1m"
ESC_FAINT="\E[2m"
ESC_ITALIC="\E[3m"
ESC_UNDERLINE="\E[4m"
ESC_FG_RED="\E[31m"
ESC_FG_GREEN="\E[32m"
ESC_FG_YELLOW="\E[33m"
ESC_FG_BLUE="\E[34m"
ESC_FG_MAGENTA="\E[35m"
ESC_FG_CYAN="\E[36m"
ESC_FG_WHITE="\E[37m"
ESC_RESET="\E[0m"
# ------------------------------------------------------------------------------
# PRINTLN:
# ------------------------------------------------------------------------------
function printLn {
char="-"
if [[ $# == 1 ]] ; then
char="$1"
fi
echo -en "${ESC_FAINT}"
for (( i=0; i< ${COLUMNS}; i++ )) ; do
echo -en "${char}"
done
echo -e "${ESC_RESET}"
}
# ------------------------------------------------------------------------------
# QUIT:
# ------------------------------------------------------------------------------
function quit {
input=""
while ([ "$input" != "q" ] && [ "$input" != "y" ]); do
echo -ne "> Continue? Enter [${ESC_BOLD}q${ESC_RESET}] to quit, [${ESC_BOLD}y${ESC_RESET}] to continue: ";
read input;
done
# printf '%*s\n' "${COLUMNS:-$(tput cols)}" '' | tr ' ' -
if [ "$input" == "q" ] ; then
printLn
echo -e "> ${ESC_BOLD}Aborting due to user input.${ESC_RESET}"
exit
fi
}
# ------------------------------------------------------------------------------
# BANNER:
# ------------------------------------------------------------------------------
function printBanner {
figlet -w 180 "/${MODULE_NAME}:>>>${SCRIPT_NAME}..." 2> /dev/null
if [ $? -ne 0 ]; then
banner "${SCRIPT_NAME}..." 2> /dev/null
if [ $? -ne 0 ]; then
echo -e "> ${SCRIPT_NAME}:" | tr a-z A-Z
fi
fi
}
printBanner
# ------------------------------------------------------------------------------
# HELP:
# ------------------------------------------------------------------------------
function printHelp {
printLn
echo -e "Usage: ${ESC_BOLD}${SCRIPT_NAME}${ESC_RESET}.sh [-c <command>] [-v] [-h]"
printLn
echo -e "Prints a provided coammnd to the terminal."
printLn
echo -e "${ESC_BOLD}-c <command>${ESC_RESET}: Print the provided command"
echo -e "${ESC_BOLD} -v${ESC_RESET}: Be more verbose"
echo -e "${ESC_BOLD} -h${ESC_RESET}: Print this help"
printLn
}
# ------------------------------------------------------------------------------
# ARGS:
# ------------------------------------------------------------------------------
POSITIONAL_ARGS=()
while [[ $# -gt 0 ]]; do
case $1 in
-h|--help)
printHelp
exit 0
;;
-v|--verbose)
verbose="1"
shift # Skip $1
# shift # Skip $2 if $1 has an argument
;;
-c|--command)
command="$2"
shift # Skip $1
shift # Skip $2 being argument of $1
;;
-*|--*)
printHelp
echo -e "> Unknown argument <${ESC_BOLD}${ESC_FG_RED}$1${ESC_RESET}>!"
exit 1
;;
*)
POSITIONAL_ARGS+=("$1") # Save positional arg
shift # Past argument
;;
esac
done
set -- "${POSITIONAL_ARGS[@]}"
# ------------------------------------------------------------------------------
# MAIN:
# ------------------------------------------------------------------------------
if [ ! -z "$command" ]; then
echo -n -e "Running command <${ESC_BOLD}${command}${ESC_RESET}>"
if [[ "$verbose" == "1" ]]; then
echo -n " in verbose mode"
fi
echo " ..."
fi
if [ -z "$command" ] && [[ "$verbose" == "1" ]]; then
echo "Running in verbose mode ..."
fi
if [ -z "$verbose" ] && [ -z "$command" ]; then
printHelp
echo "> Please provide valid arguments!"
exit 1
fi
echo "<--| Put your stuff here (remove this line) |-->"
Echo
“… echo - display a line of text …” (from
man echo
)
Echo new lines
text="line1\nline2\nline3\n"
echo -e "${text}"
The
-e
switch enablesecho
“the interpretation of the following backslash escapes”.
Don’t echo new lines
text="line1\nline2\nline3\n"
echo "${text}"
Echo to standard error
echo "Error" >&2
>&2 echo "Error"
Echo to standard out
echo "Standard out"
Echo to standard out and standard error
echo "Error and out" 1>&2;
Echo ANSI escape codes
ANSI escape codes
can be used to output text in various colors:
echo -e "\033[0;31m<<<Red foreground>>>\033[0m"
echo -e "\033[0;32m<<<Green foreground>>>\033[0m"
echo -e "\033[0;34m<<<Blue foreground>>>\033[0m"
echo -e "\033[30;48;5;1m<<<Red background, black foreground>>>\033[0m"
echo -e "\033[30;48;5;2m<<<Green background, black foreground>>>\033[0m"
echo -e "\033[30;48;5;4m<<<Blue background, black foreground>>>\033[0m"
The sequence
\033[0m
resets the escape codes being set before. The-e
switch enablesecho
“the interpretation of the following backslash escapes”. For more effects see alsobash:tip_colors_and_formatting
byFLOZz' MISC
.
Files
“… A computer file is a computer resource for recording data discretely in a computer storage device. …” (see Computer file - Wikipedia)
Read all lines of a file
This one reads all lines of a file, including the last one not terminated with a new line:
while IFS='' read -r line || [[ -n "$line" ]]; do
echo "${line}"
done < "/path/to/my/file.txt"
IFS
stands forinternal field separator
and is used by the shell to determine how to do word splitting and recognize word boundaries. For other usages ofread
see the section onread
.
Rename all files or folders recursively
Given you want to rename multiple files in a folder recursicely by a given pattern (e.g. you want to replace “foo
” by “bar
” in the files’ or folders’ name), you may go as follows (the below example just renames folders):
find . -type d -iname '*foo*' -exec bash -c 'mv "$1" "${1//foo/bar}"' -- {} \;
You may require multiple runs as renaming a folder during a find operation may cause the find
command to loos track of its succeeding folders!
If you want to go for files, you change the argument
-type
from-type d
to-type f
. If you ommit the-type
argument, then files as well as folders matching the provided patterns are processed!
Functions
“… Shell functions are a way to group commands for later execution using a single name for the group. They are executed just like a “regular” command…” (see Shell Functions (Bash Reference Manual))
Ask for continue/quit:
The below function asks whether to continue c
or to quit q
. The shell script will exit upon choosing q
or ask again till either c
or q
is pressed:
function quit? {
input=""
while ([ "$input" != "q" ] && [ "$input" != "y" ]); do
echo -ne "\E[32mContinue? Enter [q] to quit, [y] to continue:\E[0m ";
read input;
done
# printf '%*s\n' "${COLUMNS:-$(tput cols)}" '' | tr ' ' -
if [ "$input" == "q" ] ; then
echo -e "> \E[31mAborting due to user input.\E[0m"
exit
fi
}
Print separator line
The below function prints a separator line using the whole width of your terminal:
function printLn {
printf '%*s' "${COLUMNS:-$(tput cols)}" '' | tr ' ' -
}
On Windows this spawns a lot hove heavy weight processes (not threads!), noticeably slowing down your Cygwin console, therefore I personally go for this one:
if [ -z ${COLUMNS} ] ; then
export COLUMNS=$(tput cols)
fi
function printLn {
for (( i=0; i< ${COLUMNS}; i++ )) ; do
echo -n '-'
done
echo ""
}
First make sure that the
COLUMNS
environment variable is set correctly, then use it in theprintLn
function. You can also set (refresh) theCOLUMNS
environment variable in theprintLn
function if you expect resizing of your terminal during execution.
If
“… At times you need to specify different courses of action to be taken in a shell script, depending on the success or failure of a command …” (see Introduction to if - Bash Guide for Beginners
If on sub-string
Tests if a string begins with some substring:
if [[ $line = foo* ]] ; then
echo "Starts with \"foo\" !"
fi
If on empty variable
Tests whether a variable does not exist or is empty.
if [ -z "${var}" ] ; then
...
fi
If on existing variable
Tests whether a variable exist and is not empty.
if [ -n "${var}" ] ; then
...
fi
If on status code
Control flow depending of the error code of a called command:
false
if [ $? -ne 0 ]; then
echo "Error!"
exit 1
fi
echo "No error :-)"
true
if [ $? -ne 0 ]; then
echo "Error!"
exit 1
fi
echo "No error :-)"
A status code can also be forced instead of calling a command by issuing a
true
or afalse
, see allso the chapter on Status codes.
If on file exists
Test whether a file exists or not:
if [ -f /tmp/foo.txt ]; then
echo "File found!"
fi
Negate the
if
statatement with the exclemation mark!
as follows:if [ ! -f /tmp/foo.txt ]; ...
If on directory exists
Test whether a directory exists or not:
if [ -d /home/nakatomi/tmp ]; then
echo "Directoy exists!"
fi
Negate the
if
statatement with the exclemation mark!
as follows:if [ ! -d /home/nakatomi/tmp ]; ...
Internal field separator (IFS)
IFS
stands for internal field separator
and is used by the shell to determine how to do word splitting and recognize word boundaries.
mystring="A:B C D"
IFS=' '; for word in $mystring; do echo "Word: $word"; done
IFS=':'; for word in $mystring; do echo "Word: $word"; done
Internal variales
There are some reserved bash variables with special values, the so called internal vairables:
Variable | Behhaviour |
---|---|
$0 |
Name of the shell script when invoked from within a bash script, else the name of the shell when invoked directly from the command line |
$1 , $2 , $3 , … |
Represents the first ($1 ), the second ($2 ) and the third ($3 ) argument (and so on) being passed to your bash script or bash function (arguments from the 10th onward must be enclosed in curly braces as such: ${10} , ${11} , ${12} ) |
$* |
All arguments passed to your bash script or bash function in a single string, arguments separated by each other by a space (“ ”) character |
$# |
The number of arguments passed to your bash script or bash function |
$@ |
All arguments passed to your bash script or bash function as an array, preserving arguments of multiple words encapsulated in quotes (“" ”) as a single argument |
$? |
The status code of the last executed command |
$$ |
The PID (process ID) of the script itself |
$BASH |
The path of the bash shell itself |
$BASH_VERSION |
The version of the bash shell itself |
$FUNCNAME |
The name of the function currently being executed |
$HOME |
The home directory of the current user, something like /home/romero |
$HOSTNAME |
The name of the host the bash script is executed on |
$IFS |
The internal field separator, used by the shell to determine how to do word splitting and recognize word boundaries (see IFS ) |
$LINENO |
The line number of the bash script’s line currently being executed (actually the line number where this internal variable appears) |
$PATH |
The path where the bash shell looks for executables (binaries) or other scripts when called without a preceding path |
$PS1 |
The bash shell’s command line’s (first) prompt, can be beautified with ANSI escape codes |
$PS2 , $PS3 , $PS4 |
The secondary ($PS2 , additional input expected), tertiary ($PS3 , within a select loop which is a tool for building menus) and quaternary ($PS4 , prefix for additional printed information in case the bash shell has been invoked with the -x switch) prompt |
$PWD |
The current working directory of the bash shell (and therewith your bash script) |
$RANDOM |
Contains the last pseudo random number being continuously produced |
$SECONDS |
The number of seconds this script already runs |
$USER |
The user name of the user executing the bash script |
Line segmentation
Elements by index
Get a sub-string from a string by its index given a known delimiter:
echo "1,2,3" | cut -d ',' -f 2
echo "A B C" | cut -d ' ' -f 1
echo -e "X\tY\tZ" | cut -f 3
The
cut
command is used to extract sections from lines of input.
Numbers
Count
Increment a value:
index="1"
index=$((index+1))
Paths
Remove last part of path
Given the path /usr/local/bin
:
dirname /usr/local/bin
This will result in the output /usr/local
.
Read
“… The read utility shall read a single line from standard input. …” (from
man read
)
Halt till a key is pressed
You may halt the script till a key is pressed:
echo "Hit any key ..."
read -n 1 -s
Shebang
Depending on the shell
you want to use it looks something like this at the beginning of your script file, being introduced with a shebang
(“#!
”):
#!/bin/bash
Strings
Iterate through all lines of a string
lines=...
while IFS= read -r line; do
echo "${line}"
done <<< "${lines}"
Status codes
If on status code
See
If on status code
in theIf
chapter.
Force status code 0
true
Force status code 1
false
Text
Convert text to lower case
echo "Lower case to upper case" | tr a-z A-Z
Convert text to upper case
echo "Upper case to lower case" | tr A-Z a-z
Trap
“…
trap [-lp] [arg] [sigspec …]
… The commands inarg
are to be read and executed when the shell receives signalsigspec
…” (see Bash Reference Manual: Bourne Shell Builtins)
Trap signals
You may invoke your custom trap handler upon any occurrence of a control signal
such as Ctrl+C
, Ctrl+Y
or Ctrl+Z
:
trap "echo 'Bye bye!'" 1 2 3 6
For a list of signal numbers with the corresponding signals, please refer to Trap - Shell Scripting Tutorial or Signals - Bash Guide for Beginners.
Debug “interrupt”
Traps can be used for advanced functionality such as the “debug” interrupt:
#!/bin/bash
trap '
echo "> Executing command \"$BASH_COMMAND\", press any key to continue ..."
read -n 1 -s
' DEBUG
echo "Hello world!"
echo "Hello universe!"
Upon execution of your bash
script, the trap
handler is called after each invocation of your script’s commands, with the variable $BASH_COMMAND
containing the bash
command to be executed next. You may halt the script till a key is pressed (read -n 1 -s
).
Variable substitution
Interpret a variable’s value as variable name
Given a variable named color
contains a value which represents another variable. That other value is a color name which we want to resolve to its color value. E.g. we have a pointer to another variable in our variable named color
which resolves to a color value. Now we have some colors defined as ANSI escape codes
:
red="\E[31m"
green="\E[32m"
yellow="\E[33m"
blue="\E[34m"
magenta="\E[35m"
cyan="\E[36m"
white="\E[37m"
Next we assign our color
variable the value green
:
color="green"
Finally we want to get the ANSI escape codes
for green:
echo ${!color}
This results in the output “\E[32m
”. Now we can pass color “names” to get their ANSI escape codes
as easy as color="red"
, color="blue
or color="yellow"
and so on.
Replace first
Replace the first occurrence of a string:
text="I am a very clever person, clever, isn't it?"
result=${text/clever/dumb}
echo "${result}"
Replace all
Replace all occurrences of a string:
text="I am a very clever person, clever, isn't it?"
result=${text//clever/dumb}
echo "${result}"
Trim leading white-spaces
shopt -s extglob
output=" This is a test"
output="${output###*( )}"
shopt -u extglob
echo "${output}"
The command
shopt -s extglob
enables theextended pattern matching features
of thebash
, whereas the commandshopt -u extglob
disables it again.
Trim trailing whitespaces
shopt -s extglob
output="This is a test "
output="${output%%*( )}"
shopt -u extglob
echo "${output}"
The command
shopt -s extglob
enables theextended pattern matching features
of thebash
, whereas the commandshopt -u extglob
disables it again.