Essential Bash shell commands, keyboard shortcuts, variables, conditionals, loops, functions, pipes, and redirection. Applies to bash 4+ and zsh.
Navigation
Command
Description
pwd
Print current directory
cd <dir>
Change directory
cd ~
Go to home directory
cd -
Go to previous directory
ls
List directory contents
ls -la
List all files including hidden, long format
pushd <dir>
Push directory onto stack and cd to it
popd
Pop directory from stack and return to it
File Operations
Command
Description
cp src dst
Copy file
cp -r src dst
Copy directory recursively
mv src dst
Move or rename file/directory
rm <file>
Delete file
rm -rf <dir>
Delete directory and contents (use with care)
mkdir <dir>
Create directory
mkdir -p a/b/c
Create nested directories
touch <file>
Create empty file or update timestamp
ln -s target link
Create symbolic link
find . -name "*.log"
Find files matching pattern
chmod 755 <file>
Set file permissions
chown user:group <file>
Change file owner and group
Viewing Files
Command
Description
cat <file>
Print file contents
less <file>
Paginated viewer (q to quit, / to search)
head -n 20 <file>
Show first 20 lines
tail -n 20 <file>
Show last 20 lines
tail -f <file>
Follow file as it grows (useful for logs)
grep "pattern" <file>
Search file for pattern
grep -r "pattern" .
Recursive search in current directory
wc -l <file>
Count lines in file
sort <file>
Sort lines alphabetically
uniq
Remove duplicate adjacent lines (use after sort)
Redirection & Pipes
Syntax
Description
cmd > file
Redirect stdout to file (overwrite)
cmd >> file
Redirect stdout to file (append)
cmd < file
Feed file as stdin to cmd
cmd1 | cmd2
Pipe stdout of cmd1 to stdin of cmd2
cmd 2> err.log
Redirect stderr to file
cmd &> file
Redirect both stdout and stderr to file
cmd 2>/dev/null
Suppress stderr
cmd1 && cmd2
Run cmd2 only if cmd1 succeeds
cmd1 || cmd2
Run cmd2 only if cmd1 fails
cmd1 ; cmd2
Run both regardless of exit codes
Variables
Syntax
Description
VAR=value
Assign (no spaces around =)
$VAR or ${VAR}
Expand variable
${VAR:-default}
Use default if VAR is unset or empty
${VAR:?error}
Exit with error if VAR is unset
readonly VAR=value
Make variable read-only
export VAR
Make variable available to child processes
unset VAR
Remove variable
${#VAR}
Length of variable value
$0, $1, $2…
Script name, positional args
$@
All arguments as separate words
$#
Number of arguments
$?
Exit code of last command
$$
PID of current shell
Conditionals
# if / elif / else
if [[ "$VAR" == "hello" ]]; then
echo "greeting"
elif [[ "$VAR" == "bye" ]]; then
echo "farewell"
else
echo "other"
fi
# File tests
if [[ -f "$FILE" ]]; then echo "is a file"; fi
if [[ -d "$DIR" ]]; then echo "is a directory"; fi
if [[ -z "$STR" ]]; then echo "empty string"; fi
if [[ -n "$STR" ]]; then echo "non-empty string"; fi
if [[ -e "$PATH" ]]; then echo "exists"; fi
Test Flag
Meaning
-f
Is a regular file
-d
Is a directory
-e
Exists (file or dir)
-z
String is empty
-n
String is non-empty
-r / -w / -x
File is readable / writable / executable
-eq / -ne / -lt / -gt
Numeric: equal / not equal / less / greater
Loops
# for loop over values
for item in a b c; do
echo "$item"
done
# for loop over files
for f in *.txt; do
echo "$f"
done
# C-style for loop
for ((i=0; i<5; i++)); do
echo "$i"
done
# while loop
while [[ $count -lt 10 ]]; do
((count++))
done
# until loop
until [[ $count -ge 10 ]]; do
((count++))
done
Use the -f flag inside a conditional: if [[ -f "/path/to/file" ]]; then echo "exists"; fi. To check for a directory, use -d. To check that a path exists regardless of type, use -e. Always quote the path in case it contains spaces: [[ -f "$MYPATH" ]].
What is the difference between single and double quotes in bash?
Double quotes ("...") allow variable expansion and command substitution inside them — $VAR and $(cmd) are expanded. Single quotes ('...') treat everything literally — no expansion at all. Use double quotes when you need variable values in a string. Use single quotes when you want the exact literal string, such as regex patterns or awk scripts that contain $.
How do I loop over files in bash?
Use a glob in a for loop: for f in *.txt; do echo "$f"; done. Always quote "$f" to handle filenames with spaces. To loop recursively over all files, you can use find . -name "*.txt" -exec echo \; or enable globstar with shopt -s globstar and then use for f in **/*.txt; do ....