Cheatsheets / Bash

Bash Cheatsheet

Complete Bash scripting reference. Hit Ctrl+P to print.

Navigation & Files

pwdPrint current working directory
cd /path/to/dirChange directory
cd -Go to previous directory
cd ~Go to home directory
ls -laList files including hidden, long format
ls -lhList files with human-readable sizes
mkdir -p a/b/cCreate nested directories
rm -rf dir/Remove directory and contents recursively
cp -r src/ dest/Copy directory recursively
mv old newMove or rename file/directory
ln -s target linkCreate symbolic link
find . -name "*.log"Find files by name
find . -type f -mtime -7Find files modified in last 7 days
find . -type f -size +10MFind files larger than 10 MB
touch file.txtCreate empty file or update timestamp
stat file.txtShow file metadata (size, permissions, timestamps)
file image.pngDetect file type
du -sh dir/Disk usage of directory, human-readable
df -hDisk free space on all mounts
chmod 755 script.shSet rwxr-xr-x permissions
chmod +x script.shMake file executable
chown user:group fileChange file owner and group

Text Processing

cat file.txtPrint file contents
less file.txtPage through file (q to quit)
head -n 20 file.txtPrint first 20 lines
tail -n 20 file.txtPrint last 20 lines
tail -f file.logFollow file as it grows
grep "pattern" file.txtSearch for pattern in file
grep -r "pattern" dir/Recursive search in directory
grep -i "pattern" fileCase-insensitive search
grep -v "pattern" fileInvert match - show lines NOT matching
grep -n "pattern" fileShow line numbers with matches
grep -c "pattern" fileCount matching lines
sed "s/old/new/g" fileReplace all occurrences in output
sed -i "s/old/new/g" fileReplace in file in-place
awk "{print $1}" filePrint first field of each line
awk -F: "{print $1}" /etc/passwdSet field separator to :
cut -d: -f1 /etc/passwdCut field 1 with : delimiter
sort file.txtSort lines alphabetically
sort -n -k2 file.txtSort numerically by second field
sort -rn file.txtSort numerically, descending
uniq file.txtRemove consecutive duplicate lines
sort file.txt | uniq -cCount occurrences of each unique line
wc -l file.txtCount lines
wc -w file.txtCount words
tr "a-z" "A-Z"Translate characters (stdin)
xargs rmPass stdin lines as arguments to command
tee output.txtWrite stdin to file AND stdout

Variables & Expansion

name="Alice"Assign variable - no spaces around =
echo "$name"Expand variable (double quotes preserve spaces)
echo "${name}"Explicit variable boundary - preferred in strings
echo "${name:-default}"Use default if name is unset or empty
echo "${name:=default}"Assign default if name is unset or empty
echo "${#name}"Length of variable value
echo "${name:2:5}"Substring: offset 2, length 5
echo "${name/old/new}"Replace first occurrence in value
echo "${name//old/new}"Replace all occurrences in value
echo "${name^^}"Uppercase all characters
echo "${name,,}"Lowercase all characters
readonly PI=3.14Declare read-only variable
export VAR=valueExport variable to child processes
unset nameRemove variable
result=$(command)Command substitution - capture output
result=$((3 + 4))Arithmetic expansion
echo {a,b,c}.txtBrace expansion: a.txt b.txt c.txt
echo {1..5}Brace sequence: 1 2 3 4 5
$0, $1, $2Script name, first arg, second arg
$#Number of arguments
"$@"All arguments as separate words
"$*"All arguments as single string
$?Exit status of last command
$$PID of current shell
$!PID of last background process
declare -i num=5Declare integer variable
declare -a arr=(1 2 3)Declare indexed array
declare -A map=([key]=val)Declare associative array

Arrays

arr=(one two three)Create indexed array
arr[0]="one"Assign element by index
echo "${arr[0]}"Access element at index 0
echo "${arr[@]}"All elements
echo "${#arr[@]}"Array length
arr+=("four")Append element
unset arr[1]Remove element at index 1
echo "${arr[@]:1:2}"Slice: 2 elements starting at index 1
for item in "${arr[@]}"; doIterate over array elements
declare -A mapDeclare associative array (hash map)
map[key]="value"Assign associative array entry
echo "${map[key]}"Access associative array entry
echo "${!map[@]}"All keys of associative array
echo "${map[@]}"All values of associative array

Control Flow

if [ "$x" -eq 1 ]; then ... fiif statement
if [[ "$s" == "hi" ]]; then[[ ]] - preferred: handles regex, no word splitting
if [[ -z "$s" ]]; then-z true if string is empty
if [[ -n "$s" ]]; then-n true if string is non-empty
if [[ "$a" == "$b" ]]; thenString equality
if [[ "$n" -gt 5 ]]; then-gt -lt -ge -le -eq -ne for integers
if [[ -f file ]]; then-f true if file exists and is regular file
if [[ -d dir ]]; then-d true if directory exists
if [[ -e path ]]; then-e true if path exists (any type)
if [[ -r file ]]; then-r -w -x: readable, writable, executable
if cmd; then ... else ... fiBranch on command exit status
cmd1 && cmd2Run cmd2 only if cmd1 succeeds
cmd1 || cmd2Run cmd2 only if cmd1 fails
for i in 1 2 3; do echo $i; donefor loop over list
for i in {1..10}; dofor loop over range
for ((i=0; i<5; i++)); doC-style for loop
while [[ $n -gt 0 ]]; dowhile loop
until [[ $n -eq 0 ]]; dountil loop - runs while condition is false
break / continueExit loop / skip to next iteration
case "$var" in foo) ;; bar) ;; *) ;; esaccase statement - pattern matching
select opt in a b c; do ... doneInteractive menu (sets $REPLY)

Functions

greet() { echo "Hello $1"; }Define function
function greet { echo "Hello $1"; }Alternate definition syntax
greet "Alice"Call function with argument
local name="Alice"Local variable - scoped to function
return 0Return exit code (0 = success, 1+ = error)
result=$(my_func)Capture function output via command substitution
my_func "$@"Forward all script arguments to function
type greetCheck if name is function, builtin, or command
unset -f greetRemove function definition

Redirection & Pipes

cmd > fileRedirect stdout to file (overwrite)
cmd >> fileRedirect stdout to file (append)
cmd < fileRead stdin from file
cmd 2> err.logRedirect stderr to file
cmd 2>&1Redirect stderr to same destination as stdout
cmd > out.log 2>&1Redirect both stdout and stderr to file
cmd &> fileShorthand: redirect both stdout and stderr
cmd > /dev/nullDiscard stdout
cmd1 | cmd2Pipe stdout of cmd1 to stdin of cmd2
cmd1 |& cmd2Pipe both stdout and stderr to cmd2
cat <<EOF ... EOFHere-doc: multi-line string as stdin
cmd <<< 'string'Here-string: pass string as stdin
exec 3> file.txtOpen file descriptor 3 for writing
echo "hi" >&3Write to file descriptor 3
exec 3>&-Close file descriptor 3

Process & Job Control

cmd &Run command in background
jobsList background jobs
fg %1Bring job 1 to foreground
bg %1Resume job 1 in background
Ctrl+ZSuspend foreground job
Ctrl+CSend SIGINT to foreground process
kill PIDSend SIGTERM to process
kill -9 PIDSend SIGKILL - force terminate
kill %1Kill job by job number
pkill nameKill processes by name
killall nameKill all processes with given name
ps auxList all running processes
ps aux | grep phpFind PHP processes
pgrep nameGet PID(s) by process name
top / htopInteractive process viewer
waitWait for all background jobs to complete
wait $!Wait for last background process
nohup cmd &Run command immune to hangup
disown %1Remove job from shell job table
trap "cleanup" EXITRun function on shell exit
trap "handler" INT TERMHandle SIGINT and SIGTERM signals

Archives & Compression

tar -czf archive.tar.gz dir/Create gzip-compressed archive
tar -cjf archive.tar.bz2 dir/Create bzip2-compressed archive
tar -cJf archive.tar.xz dir/Create xz-compressed archive
tar -czf archive.tar.gz -C /parent dir/Archive relative to parent directory
tar -xzf archive.tar.gzExtract gzip archive in current directory
tar -xzf archive.tar.gz -C /dest/Extract to specific directory
tar -tzf archive.tar.gzList contents without extracting
tar -xzf archive.tar.gz file.txtExtract single file from archive
tar -czf - dir/ | ssh host "cat > out.tar.gz"Stream archive over SSH
gzip file.txtCompress file → file.txt.gz (removes original)
gzip -k file.txtCompress and keep original
gzip -d file.txt.gz / gunzip file.txt.gzDecompress .gz file
gzip -9 file.txtMaximum compression level
zcat file.txt.gzPrint contents of .gz without extracting
zip -r archive.zip dir/Create zip archive recursively
zip -r archive.zip dir/ -x "*.git*"Zip excluding a pattern
unzip archive.zipExtract zip archive
unzip archive.zip -d /dest/Extract zip to specific directory
unzip -l archive.zipList zip contents without extracting

Networking & Remote

curl https://example.comFetch URL and print to stdout
curl -o file.zip https://example.com/file.zipDownload URL to file
curl -O https://example.com/file.zipDownload URL keeping remote filename
curl -L urlFollow redirects
curl -s urlSilent mode - suppress progress
curl -I urlFetch headers only (HEAD request)
curl -X POST -H "Content-Type: application/json" -d '{"key":"val"}' urlPOST JSON data
curl -u user:pass urlHTTP Basic authentication
curl -H "Authorization: Bearer $TOKEN" urlBearer token header
wget urlDownload URL to current directory
wget -q -O - urlFetch URL quietly to stdout
wget -r -np urlRecursive download, no parent dirs
ssh user@hostConnect to remote host
ssh -p 2222 user@hostConnect on non-default port
ssh -i ~/.ssh/key.pem user@hostConnect with specific identity file
ssh -L 8080:localhost:80 user@hostLocal port forwarding
ssh -R 9090:localhost:3000 user@hostRemote port forwarding
scp file.txt user@host:/remote/path/Copy file to remote host
scp user@host:/remote/file.txt .Copy file from remote host
scp -r dir/ user@host:/remote/Copy directory recursively
rsync -avz dir/ user@host:/remote/Sync directory to remote (archive, verbose, compress)
rsync -avz --delete dir/ user@host:/remote/Sync and delete files not in source
rsync -avz --exclude="*.log" dir/ dest/Sync excluding pattern
rsync -n dir/ dest/Dry run - show what would change
ping -c 4 hostPing host 4 times
ss -tulpnShow listening TCP/UDP ports and processes
netstat -tulpnSame as ss -tulpn (older systems)

Scripting Patterns

#!/usr/bin/env bashShebang - portable bash path
set -euo pipefailExit on error, unset var, pipe failure
set -xPrint each command before executing (debug)
set +xDisable command tracing
echo "msg" >&2Write error message to stderr
exit 1Exit script with non-zero status
[[ "${BASH_SOURCE[0]}" == "$0" ]]True if script is run directly, not sourced
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"Absolute path to script directory
source ./lib.sh / . ./lib.shSource a script into current shell
mktempCreate a secure temporary file
mktemp -dCreate a secure temporary directory
printf "%-10s %s\n" "$a" "$b"Formatted output
read -p "Name: " nameRead user input into variable
read -s -p "Password: " passRead silently (no echo)
getopts "ab:c" optParse short flags; : means arg required
command -v gitCheck if command exists (returns path)
hash git 2>/dev/nullCheck if command is in PATH