# Bash — Shell Scripting and Interactive Command Line

> Practical guide to Bash: variables, parameter expansion, loops, functions, redirection and robust scripts with set -euo pipefail.

Source: https://www.jpkc.com/db/en/cheatsheets/shell-system/bash/

<!-- PROSE:intro -->
Bash is the default shell on most Linux distributions and, at the same time, a full-fledged scripting language. Whether you work interactively at the command line or write automation scripts, variables, parameter expansion, loops and functions are your daily bread. This guide gathers the building blocks you actually need: from string manipulation through redirection and process control to robust scripting patterns. Keep the difference between interactive and script use in mind – both follow the same rules but place different demands on you.
<!-- PROSE:intro:end -->

## Variables & Strings

`VAR='value'` — Assign a variable. No spaces around the equals sign.

```bash
NAME='World'
```

`echo "$VAR"` — Expand variable inside double quotes. Single quotes prevent expansion.

```bash
echo "Hello $NAME"
```

`echo "${VAR}text"` — Use braces to delimit variable name from surrounding text.

```bash
echo "${NAME}_backup"
```

`readonly VAR='value'` — Declare a read-only (constant) variable.

```bash
readonly PI='3.14159'
```

`unset VAR` — Remove a variable.

```bash
unset TEMP_FILE
```

`export VAR='value'` — Export variable to child processes (environment variable).

```bash
export PATH="$HOME/bin:$PATH"
```

`local VAR='value'` — Declare a local variable inside a function.

```bash
local count=0
```

## Parameter Expansion

`${VAR:-default}` — Use default value if variable is unset or empty.

```bash
echo "${USER:-anonymous}"
```

`${VAR:=default}` — Assign default value if variable is unset or empty.

```bash
echo "${LANG:=en_US.UTF-8}"
```

`${VAR:+alternate}` — Use alternate value if variable is set and non-empty.

```bash
echo "${DEBUG:+--verbose}"
```

`${VAR:?error message}` — Print error and exit if variable is unset or empty.

```bash
${API_KEY:?API_KEY must be set}
```

`${#VAR}` — Get the length of a string variable.

```bash
echo "Length: ${#NAME}"
```

`${VAR^^} / ${VAR,,}` — Convert to uppercase / lowercase (Bash 4+).

```bash
echo "${name^^}"  # HELLO
```

## String Manipulation

`${VAR#pattern}` — Remove shortest match of pattern from the beginning.

```bash
FILE='archive.tar.gz'; echo "${FILE#*.}"  # tar.gz
```

`${VAR##pattern}` — Remove longest match of pattern from the beginning.

```bash
PATH='/home/user/file.txt'; echo "${PATH##*/}"  # file.txt
```

`${VAR%pattern}` — Remove shortest match of pattern from the end.

```bash
FILE='photo.jpg'; echo "${FILE%.*}"  # photo
```

`${VAR%%pattern}` — Remove longest match of pattern from the end.

```bash
FILE='backup.tar.gz'; echo "${FILE%%.*}"  # backup
```

`${VAR/pattern/replacement}` — Replace first occurrence of pattern.

```bash
echo "${STR/foo/bar}"
```

`${VAR//pattern/replacement}` — Replace all occurrences of pattern.

```bash
echo "${PATH//:/ }"
```

`${VAR:offset:length}` — Extract substring starting at offset with given length.

```bash
STR='Hello World'; echo "${STR:6:5}"  # World
```

## Arrays

`ARR=(val1 val2 val3)` — Declare an indexed array.

```bash
COLORS=(red green blue)
```

`echo "${ARR[0]}"` — Access array element by index (0-based).

```bash
echo "${COLORS[1]}"  # green
```

`echo "${ARR[@]}"` — Expand all array elements.

```bash
echo "${COLORS[@]}"
```

`echo "${#ARR[@]}"` — Get the number of elements in an array.

```bash
echo "${#COLORS[@]}"  # 3
```

`ARR+=(val4)` — Append an element to an array.

```bash
COLORS+=(yellow)
```

`declare -A MAP` — Declare an associative array (Bash 4+).

```bash
declare -A PORTS; PORTS[http]=80; PORTS[https]=443
```

`for item in "${ARR[@]}"; do ... done` — Iterate over all array elements.

```bash
for c in "${COLORS[@]}"; do echo "$c"; done
```

## Conditionals

`if [[ condition ]]; then ... fi` — Basic if statement with extended test brackets.

```bash
if [[ -f 'config.txt' ]]; then echo 'Found'; fi
```

`if [[ cond ]]; then ... else ... fi` — If-else statement.

```bash
if [[ $# -gt 0 ]]; then echo "$1"; else echo 'No args'; fi
```

`[[ -f <file> ]]` — Test if file exists and is a regular file.

```bash
[[ -f /etc/hosts ]] && echo 'Exists'
```

`[[ -d <dir> ]]` — Test if directory exists.

```bash
[[ -d /tmp ]] && echo 'Directory exists'
```

`[[ -z "$VAR" ]]` — Test if string is empty (zero length).

```bash
[[ -z "$INPUT" ]] && echo 'Empty input'
```

`[[ -n "$VAR" ]]` — Test if string is non-empty.

```bash
[[ -n "$USER" ]] && echo "User: $USER"
```

`[[ "$A" == "$B" ]]` — String equality comparison.

```bash
[[ "$answer" == 'yes' ]] && proceed
```

`[[ "$A" =~ regex ]]` — Regex match test (extended regex).

```bash
[[ "$email" =~ ^[a-z]+@[a-z]+\.[a-z]+$ ]] && echo 'Valid'
```

## Loops

`for VAR in list; do ... done` — Iterate over a list of items.

```bash
for f in *.txt; do echo "$f"; done
```

`for (( i=0; i<n; i++ )); do ... done` — C-style for loop with counter.

```bash
for (( i=1; i<=5; i++ )); do echo "$i"; done
```

`for VAR in {start..end}; do ... done` — Iterate over a range of numbers using brace expansion.

```bash
for i in {1..10}; do echo "$i"; done
```

`while [[ condition ]]; do ... done` — Loop while condition is true.

```bash
while [[ $count -lt 10 ]]; do ((count++)); done
```

`while read -r line; do ... done < <file>` — Read a file line by line.

```bash
while read -r line; do echo "$line"; done < data.txt
```

`<command> | while read -r line; do ... done` — Process command output line by line.

```bash
find . -name '*.log' | while read -r f; do wc -l "$f"; done
```

`until [[ condition ]]; do ... done` — Loop until condition becomes true.

```bash
until [[ -f /tmp/ready ]]; do sleep 1; done
```

## Functions

`fname() { ... }` — Define a function. Preferred syntax over function keyword.

```bash
greet() { echo "Hello, $1"; }
```

`$1, $2, ..., $@, $#` — Access function arguments. $@ is all args, $# is argument count.

```bash
add() { echo $(( $1 + $2 )); }; add 3 5
```

`return <n>` — Return an exit status from a function (0-255). Use echo for values.

```bash
is_root() { [[ $EUID -eq 0 ]] && return 0 || return 1; }
```

`result=$(fname arg)` — Capture function output in a variable using command substitution.

```bash
upper() { echo "${1^^}"; }; NAME=$(upper 'hello')
```

## Arithmetic

`$(( expression ))` — Arithmetic expansion. Supports +, -, *, /, %, **.

```bash
echo "$(( 5 + 3 ))"  # 8
```

`(( VAR++ )) / (( VAR-- ))` — Increment / decrement a variable.

```bash
count=0; (( count++ )); echo "$count"  # 1
```

`(( VAR += n ))` — Compound assignment operators (+=, -=, *=, /=, %=).

```bash
total=100; (( total -= 25 )); echo "$total"  # 75
```

`$(( RANDOM % n ))` — Generate a random number between 0 and n-1.

```bash
echo "Dice: $(( RANDOM % 6 + 1 ))"
```

## Redirection & Pipes

`cmd > file` — Redirect stdout to a file (overwrite).

```bash
echo 'hello' > output.txt
```

`cmd >> file` — Redirect stdout to a file (append).

```bash
echo 'line' >> log.txt
```

`cmd 2> file` — Redirect stderr to a file.

```bash
find / -name '*.conf' 2> /dev/null
```

`cmd &> file` — Redirect both stdout and stderr to a file.

```bash
make &> build.log
```

`cmd 2>&1` — Redirect stderr to stdout (combine streams).

```bash
command 2>&1 | tee output.log
```

`cmd1 | cmd2` — Pipe stdout of cmd1 to stdin of cmd2.

```bash
ps aux | grep nginx
```

`cmd1 |& cmd2` — Pipe both stdout and stderr to cmd2.

```bash
make |& less
```

`cmd <<< 'string'` — Here-string. Pass a string as stdin to a command.

```bash
grep 'error' <<< "$log_output"
```

## Process Control

`cmd &` — Run command in the background.

```bash
sleep 60 &
```

`jobs` — List background jobs in the current shell.

```bash
jobs -l
```

`fg %<n>` — Bring background job number n to the foreground.

```bash
fg %1
```

`bg %<n>` — Resume a stopped job in the background.

```bash
bg %1
```

`wait [pid]` — Wait for background process to finish. No argument waits for all.

```bash
cmd1 & cmd2 &; wait
```

`$!` — PID of the last background process.

```bash
server & echo "PID: $!"
```

`$$` — PID of the current shell.

```bash
echo "Script PID: $$"
```

`trap 'cmd' SIGNAL` — Execute command when a signal is received.

```bash
trap 'rm -f /tmp/lockfile; exit' EXIT INT TERM
```

## Command Chaining

`cmd1 && cmd2` — Run cmd2 only if cmd1 succeeds (exit code 0).

```bash
mkdir build && cd build
```

`cmd1 || cmd2` — Run cmd2 only if cmd1 fails (non-zero exit code).

```bash
grep -q 'error' log.txt || echo 'No errors'
```

`cmd1; cmd2` — Run cmd2 after cmd1 regardless of exit status.

```bash
echo 'Start'; date; echo 'End'
```

`{ cmd1; cmd2; }` — Group commands in the current shell (note trailing semicolon and spaces).

```bash
{ echo 'Header'; cat data.txt; } > report.txt
```

`(cmd1; cmd2)` — Run commands in a subshell (does not affect parent).

```bash
(cd /tmp && tar xzf archive.tar.gz)
```

## Special Variables

`$?` — Exit status of the last command (0 = success).

```bash
grep -q 'root' /etc/passwd; echo "$?"
```

`$0` — Name of the current script or shell.

```bash
echo "Script: $0"
```

`$# / $@ / $*` — Number of arguments / all arguments (as separate words / as single word).

```bash
echo "$# arguments: $@"
```

`$_` — Last argument of the previous command.

```bash
mkdir mydir; cd "$_"
```

`$RANDOM` — Random integer between 0 and 32767.

```bash
echo "$RANDOM"
```

`$SECONDS` — Seconds since shell was started. Can be reset.

```bash
SECONDS=0; sleep 2; echo "Elapsed: ${SECONDS}s"
```

`$LINENO` — Current line number in the script.

```bash
echo "Error at line $LINENO"
```

## Keyboard Shortcuts

`Ctrl+R` — Reverse search through command history.

```bash
Ctrl+R, then type part of a previous command
```

`Ctrl+A / Ctrl+E` — Move cursor to beginning / end of line.

```bash
Ctrl+A to jump to start
```

`Ctrl+W / Alt+D` — Delete word before / after cursor.

```bash
Ctrl+W to delete previous word
```

`Ctrl+U / Ctrl+K` — Delete from cursor to beginning / end of line.

```bash
Ctrl+U to clear everything before cursor
```

`Ctrl+Y` — Paste (yank) text previously cut with Ctrl+U/K/W.

```bash
Ctrl+U then Ctrl+Y to restore
```

`Ctrl+L` — Clear the screen (same as clear command).

```bash
Ctrl+L
```

`Ctrl+Z` — Suspend the current foreground process.

```bash
Ctrl+Z, then bg to resume in background
```

`!! / !<n> / !<string>` — Re-run last command / command #n / last command starting with string.

```bash
sudo !!
```

## Common Patterns

`set -euo pipefail` — Strict mode: exit on error, undefined vars, and pipe failures.

```bash
#!/bin/bash
set -euo pipefail
```

`DIR="$(cd "$(dirname "$0")" && pwd)"` — Get the directory of the current script reliably.

```bash
DIR="$(cd "$(dirname "$0")" && pwd)"
```

`[[ -f file ]] || { echo 'Missing'; exit 1; }` — Guard clause: exit early if a required file is missing.

```bash
[[ -f config.yml ]] || { echo 'Config not found'; exit 1; }
```

`while IFS=',' read -r col1 col2; do ... done < file` — Parse CSV or delimited data line by line.

```bash
while IFS=',' read -r name age; do echo "$name is $age"; done < people.csv
```

`command -v <cmd> &> /dev/null` — Check if a command is available on the system.

```bash
command -v docker &> /dev/null || echo 'Docker not installed'
```

`mktemp` — Create a temporary file safely and print its path.

```bash
TMP=$(mktemp); echo 'data' > "$TMP"; rm "$TMP"
```

<!-- PROSE:outro -->
## Conclusion

Bash carries you from a quick one-liner pipeline all the way to a full-blown deployment script. For interactive work, keyboard shortcuts, history expansion and pipes matter most; for scripts, parameter expansion, arrays and clean functions make the difference. Enable `set -euo pipefail` in every serious script so errors don't slip through silently, and quote your variables consistently (`"$VAR"`) to avoid word-splitting and globbing surprises. Remember where your configuration lives, too: `~/.bashrc` applies to interactive non-login shells, `~/.bash_profile` to login shells – mixing the two leaves you puzzled over missing aliases or PATH entries.

## Further Reading

- [GNU Bash Reference Manual](https://www.gnu.org/software/bash/manual/) – the official, complete reference for every Bash feature
- [BashGuide (Greg's Wiki)](https://mywiki.wooledge.org/BashGuide) – a well-regarded, practical introduction to Bash scripting
- [ShellCheck](https://www.shellcheck.net/) – online linter that catches common mistakes in shell scripts
<!-- PROSE:outro:end -->

## Related Commands

- [zsh](https://www.jpkc.com/db/en/cheatsheets/shell-system/zsh/) – the Z shell, an extended interactive shell with rich completion
- [fish](https://www.jpkc.com/db/en/cheatsheets/shell-system/fish/) – the user-friendly shell with syntax highlighting out of the box
- [jobs](https://www.jpkc.com/db/en/cheatsheets/shell-system/jobs/) – manage background and stopped jobs in the current shell

