env.dev

Bash Scripting Cheat Sheet

Quick reference for Bash scripting: variables, parameter expansion, conditionals, loops, functions, arrays, redirection, error handling, and strict mode.

Last updated:

Bash scripting is the foundation of Unix/Linux automation — from simple one-liners to full deployment scripts. This cheat sheet covers essential Bash syntax: variables, conditionals, loops, functions, arrays, parameter expansion, redirection, and error handling. Organized by concept for fast lookup when writing or debugging shell scripts.

Variables and Quoting

SyntaxDescription
name="value"Assign a variable (no spaces around =)
$name or ${name}Expand a variable
readonly name="val"Declare a read-only (constant) variable
local name="val"Declare a function-local variable
export name="val"Export variable to child processes
unset nameRemove a variable
"double quotes"Allow variable expansion and command substitution
'single quotes'Literal string — no expansion at all
$(command)Command substitution — capture output of a command
$((expression))Arithmetic expansion — e.g. $((a + b))

How Do You Use Special Variables?

VariableDescription
$0Name of the script or shell
$1, $2, ...Positional parameters (arguments passed to script/function)
$#Number of positional parameters
$@All positional parameters as separate words
$*All positional parameters as a single word
$?Exit status of the last command (0 = success)
$$PID of the current shell
$!PID of the last background process
$_Last argument of the previous command
${PIPESTATUS[@]}Array of exit statuses from the last pipeline

Parameter Expansion

ExpressionDescription
${var:-default}Use "default" if var is unset or null
${var:=default}Assign "default" if var is unset or null
${var:+value}Use "value" only if var is set (not null)
${var:?error msg}Print error and exit if var is unset or null
${#var}Length of the string in var
${var:offset:length}Substring extraction — e.g. ${name:0:3}
${var#pattern}Remove shortest matching prefix
${var##pattern}Remove longest matching prefix
${var%pattern}Remove shortest matching suffix
${var%%pattern}Remove longest matching suffix
${var/old/new}Replace first occurrence of "old" with "new"
${var//old/new}Replace all occurrences of "old" with "new"
${var,,}Convert entire string to lowercase
${var^^}Convert entire string to uppercase

Conditionals and Test Expressions

SyntaxDescription
if [[ cond ]]; then ... fiBasic if statement
if [[ cond ]]; then ... elif [[ cond ]]; then ... else ... fiFull if/elif/else block
[[ -z "$str" ]]True if string is empty
[[ -n "$str" ]]True if string is not empty
[[ "$a" == "$b" ]]String equality
[[ "$a" != "$b" ]]String inequality
[[ "$str" =~ regex ]]Regex match (extended regex)
[[ $num -eq $num2 ]]Numeric equality (-ne, -lt, -le, -gt, -ge)
(( num < num2 ))Arithmetic comparison (supports <, >, <=, >=, ==, !=)
[[ cond1 && cond2 ]]Logical AND inside [[ ]]
[[ cond1 || cond2 ]]Logical OR inside [[ ]]
[[ ! cond ]]Logical NOT

File Test Operators

TestDescription
[[ -e "$file" ]]File exists (any type)
[[ -f "$file" ]]Regular file exists
[[ -d "$dir" ]]Directory exists
[[ -r "$file" ]]File is readable
[[ -w "$file" ]]File is writable
[[ -x "$file" ]]File is executable
[[ -s "$file" ]]File exists and is not empty
[[ -h "$file" ]]File is a symbolic link
[[ "$f1" -nt "$f2" ]]f1 is newer than f2
[[ "$f1" -ot "$f2" ]]f1 is older than f2

How Do You Write Loops in Bash?

PatternDescription
for item in list; do ... doneIterate over a list of words
for file in *.txt; do ... doneIterate over files matching a glob
for i in {1..10}; do ... doneIterate over a numeric range
for i in {0..20..5}; do ... doneRange with step — 0, 5, 10, 15, 20
for ((i=0; i<10; i++)); do ... doneC-style for loop
while [[ cond ]]; do ... doneWhile loop — runs while condition is true
until [[ cond ]]; do ... doneUntil loop — runs until condition is true
while read -r line; do ... done < fileRead a file line by line
while IFS=, read -r a b c; do ... done < data.csvParse CSV fields into variables
breakExit the innermost loop
continueSkip to the next iteration

Functions

SyntaxDescription
fname() { ... }Define a function (preferred POSIX form)
local var="value"Declare a local variable inside a function
$1, $2, ...Access function arguments positionally
$# inside functionNumber of arguments passed to the function
return 0Return an exit status (0-255) from a function
result=$(fname arg1)Capture function stdout as a value
fname() { echo "$1"; }; fname "hi"Define and call a function with an argument

Arrays

SyntaxDescription
arr=("a" "b" "c")Declare an indexed array
${arr[0]}Access element at index 0
${arr[-1]}Access last element
${arr[@]}All elements as separate words
${#arr[@]}Number of elements
${!arr[@]}All indices
arr+=("new")Append an element
unset arr[1]Remove element at index 1
${arr[@]:2:3}Slice — 3 elements starting at index 2
declare -A mapDeclare an associative array (dictionary)
map[key]="value"Set a key-value pair in an associative array
${map[key]}Get value by key
${!map[@]}All keys of an associative array

Redirection and Pipes

SyntaxDescription
cmd > fileRedirect stdout to file (overwrite)
cmd >> fileRedirect stdout to file (append)
cmd 2> fileRedirect stderr to file
cmd 2>&1Redirect stderr to stdout
cmd &> fileRedirect both stdout and stderr to file
cmd &>/dev/nullDiscard all output
cmd < fileRead stdin from file
cmd <<< "string"Here-string — pass string as stdin
cmd1 | cmd2Pipe stdout of cmd1 into stdin of cmd2
cmd1 |& cmd2Pipe both stdout and stderr into cmd2
diff <(cmd1) <(cmd2)Process substitution — compare output of two commands
cat <<EOF ... EOFHere-document — multi-line input block

Error Handling and Strict Mode

CommandDescription
set -eExit immediately if any command fails
set -uTreat unset variables as an error
set -o pipefailPipeline fails if any command in the pipe fails
set -euo pipefailStrict mode — combine all three above
trap "cleanup" EXITRun cleanup function on script exit
trap "echo err at $LINENO" ERRCatch errors with line number
cmd || truePrevent set -e from exiting on expected failure
cmd || { echo "failed"; exit 1; }Handle failure inline
if ! cmd; then ... fiBranch on command failure without triggering set -e

Frequently Asked Questions

What does set -euo pipefail do in Bash?

set -e exits the script on the first error, set -u treats unset variables as errors, and set -o pipefail causes a pipeline to fail if any command in it fails. Together they form "strict mode" and are recommended at the top of every Bash script to catch bugs early.

What is the difference between $@ and $* in Bash?

When double-quoted, "$@" expands each positional parameter as a separate word, preserving whitespace in arguments. "$*" joins all parameters into a single word separated by the first character of IFS. In almost all cases you want "$@" to correctly handle arguments containing spaces.

How do you check if a file exists in a Bash script?

Use if [[ -f "$file" ]]; then ... fi to check for a regular file. Use -e for any file type, -d for directories, and -s to check that a file exists and is non-empty.

How do you read a file line by line in Bash?

Use: while IFS= read -r line; do echo "$line"; done < file.txt. The -r flag prevents backslash interpretation and IFS= preserves leading/trailing whitespace. Never use "for line in $(cat file)" as it splits on words, not lines.

What is the difference between [[ ]] and [ ] in Bash?

[[ ]] is a Bash keyword that supports regex matching (=~), pattern matching, and logical operators (&&, ||) without quoting issues. [ ] (or test) is a POSIX command that requires careful quoting and uses -a/-o for logic. Prefer [[ ]] in Bash scripts for safer, more readable conditionals.

How do you pass and return values from a Bash function?

Pass values as positional arguments ($1, $2, etc.). Bash functions cannot return strings directly — "return" only sets an exit status (0-255). To return a value, echo it from the function and capture with result=$(myfunc arg1). Use local to avoid polluting the global scope.