Lately, I’ve started working on new projects that involve a lot of sysadmin responsibilities, so I need to level up my Bash skills to make my life a little easier.
Aliases already help me a lot — I’ve just figured out a system in my head, a kind of naming convention, for how I should call some daily commands that I might run hundreds of times per day.
So join me on this journey! We’ll cover not just simple aliases, but the real power of Bash scripts — a tool that can make your workflow faster, smarter, and way more fun. Enjoy! 😎
Bash (Bourne Again Shell) is the default shell for most Linux distributions and macOS systems. Mastering Bash will dramatically improve your productivity as a developer, system administrator, or power user. This comprehensive guide will take you from basic commands to advanced scripting techniques.
Table of Contents
- Getting Started with Bash
- Essential Commands
- File System Navigation
- Text Processing
- Variables and Environment
- Control Structures
- Functions
- I/O and Redirection
- Process Management
- Advanced Features
- Best Practices
- Common Pitfalls
- Conclusion
Getting Started with Bash
What is Bash?
Bash is both a command-line interface and a scripting language. It provides a powerful way to interact with your operating system, automate tasks, and create complex workflows.
Basic Syntax
Every Bash command follows this basic structure:
command [options] [arguments]
For example:
ls -la /home/user
Your First Script
Create a file with a .sh
extension:
#!/bin/bash
echo "Hello, World!"
Make it executable and run it:
chmod +x hello.sh
./hello.sh
Essential Commands
File Operations
-
ls
- List directory contents -
cp
- Copy files and directories -
mv
- Move/rename files and directories -
rm
- Remove files and directories -
mkdir
- Create directories -
rmdir
- Remove empty directories -
find
- Search for files and directories
Text Operations
-
cat
- Display file contents -
less
/more
- View file contents page by page -
head
- Display first lines of a file -
tail
- Display last lines of a file -
grep
- Search text patterns -
sed
- Stream editor for text manipulation -
awk
- Text processing tool
System Information
-
ps
- Show running processes -
top
/htop
- Display system processes -
df
- Show disk space usage -
du
- Show directory space usage -
free
- Show memory usage -
uname
- System information
File System Navigation
Basic Navigation
# Change directory
cd /path/to/directory
cd ~ # Go to home directory
cd - # Go to previous directory
# Print working directory
pwd
# List with details
ls -la
# Show hidden files
ls -a
Path Management
# Absolute path
/home/user/documents/file.txt
# Relative path
../documents/file.txt
./current-directory/file.txt
# Using wildcards
ls *.txt # All .txt files
ls file?.txt # file1.txt, fileA.txt, etc.
ls file[1-3].txt # file1.txt, file2.txt, file3.txt
Text Processing
grep - Pattern Matching
# Basic search
grep "pattern" file.txt
# Case-insensitive search
grep -i "pattern" file.txt
# Recursive search
grep -r "pattern" /directory
# Show line numbers
grep -n "pattern" file.txt
# Invert match (show non-matching lines)
grep -v "pattern" file.txt
sed - Stream Editor
# Replace first occurrence
sed 's/old/new/' file.txt
# Replace all occurrences
sed 's/old/new/g' file.txt
# Replace in-place
sed -i 's/old/new/g' file.txt
# Delete lines containing pattern
sed '/pattern/d' file.txt
# Print specific lines
sed -n '1,5p' file.txt # Print lines 1-5
awk - Text Processing
# Print specific columns
awk '{print $1, $3}' file.txt
# Print lines with condition
awk '$3 > 100' file.txt
# Sum a column
awk '{sum += $1} END {print sum}' file.txt
# Use custom delimiter
awk -F',' '{print $2}' file.csv
Variables and Environment
Variable Declaration and Usage
# Declare variables (no spaces around =)
name="John"
age=25
# Use variables
echo "Hello, $name"
echo "You are ${age} years old"
# Command substitution
current_date=$(date)
file_count=`ls | wc -l`
# Read user input
read -p "Enter your name: " username
echo "Hello, $username"
Environment Variables
# Common environment variables
echo $HOME # Home directory
echo $PATH # Executable paths
echo $USER # Current user
echo $PWD # Current directory
# Export variables to subshells
export MY_VAR="value"
# Set PATH
export PATH=$PATH:/new/directory
Special Variables
$0 # Script name
$1, $2, $3 # Script arguments
$# # Number of arguments
$@ # All arguments as separate strings
$* # All arguments as single string
$$ # Process ID
$? # Exit status of last command
Control Structures
Conditional Statements
# if-else statement
if [ condition ]; then
# commands
elif [ another_condition ]; then
# commands
else
# commands
fi
# Examples
if [ $age -gt 18 ]; then
echo "Adult"
else
echo "Minor"
fi
# String comparisons
if [ "$string1" = "$string2" ]; then
echo "Strings match"
fi
# File tests
if [ -f "/path/to/file" ]; then
echo "File exists"
fi
if [ -d "/path/to/directory" ]; then
echo "Directory exists"
fi
Loops
# for loop
for i in {1..10}; do
echo $i
done
for file in *.txt; do
echo "Processing $file"
done
# while loop
counter=1
while [ $counter -le 5 ]; do
echo $counter
((counter++))
done
# until loop
until [ $counter -gt 10 ]; do
echo $counter
((counter++))
done
Case Statements
case $variable in
pattern1)
commands
;;
pattern2|pattern3)
commands
;;
*)
default commands
;;
esac
# Example
case $1 in
start)
echo "Starting service..."
;;
stop)
echo "Stopping service..."
;;
restart)
echo "Restarting service..."
;;
*)
echo "Usage: $0 {start|stop|restart}"
;;
esac
Functions
Function Definition
# Method 1
function_name() {
# commands
return 0 # optional return value
}
# Method 2
function function_name {
# commands
}
# Example
greet() {
local name=$1
echo "Hello, $name!"
}
# Call function
greet "Alice"
Function Parameters and Local Variables
calculate_sum() {
local num1=$1
local num2=$2
local sum=$((num1 + num2))
echo $sum
}
result=$(calculate_sum 5 3)
echo "Sum: $result"
I\O and Redirection
Standard Streams
-
stdin
(0) - Standard input -
stdout
(1) - Standard output -
stderr
(2) - Standard error
Redirection
# Redirect stdout to file
command > file.txt
# Append stdout to file
command >> file.txt
# Redirect stderr
command 2> error.log
# Redirect both stdout and stderr
command > output.txt 2>&1
command &> output.txt # Bash 4+
# Redirect stdin
command < input.txt
# Here documents
cat << EOF
This is a here document
Multiple lines of text
EOF
Pipes
# Basic pipe
command1 | command2
# Chain multiple commands
ps aux | grep python | grep -v grep
# Tee - write to file and stdout
command | tee output.txt
# Process substitution
diff <(ls dir1) <(ls dir2)
Process Management
Background and Foreground Processes
# Run in background
command &
# List jobs
jobs
# Bring to foreground
fg %1
# Send to background
bg %1
# Disown process
disown %1
Process Control
# Kill process by PID
kill 1234
kill -9 1234 # Force kill
# Kill by name
killall process_name
pkill process_name
# Process information
ps aux | grep process_name
pgrep process_name
Command Execution Control
# Run commands sequentially
command1; command2; command3
# Run if previous succeeds
command1 && command2
# Run if previous fails
command1 || command2
# Group commands
(command1; command2) | command3
{ command1; command2; } | command3
Advanced Features
Arrays
# Declare array
fruits=("apple" "banana" "orange")
# Access elements
echo ${fruits[0]} # First element
echo ${fruits[@]} # All elements
echo ${fruits[*]} # All elements (different quoting behavior)
echo ${#fruits[@]} # Array length
# Add elements
fruits+=("grape")
# Loop through array
for fruit in "${fruits[@]}"; do
echo $fruit
done
String Manipulation
string="Hello, World!"
# String length
echo ${#string}
# Substring
echo ${string:0:5} # "Hello"
echo ${string:7} # "World!"
# Replace
echo ${string/Hello/Hi} # Replace first occurrence
echo ${string//o/0} # Replace all occurrences
# Remove from beginning/end
filename="document.txt"
echo ${filename%.txt} # Remove .txt extension
echo ${filename#*/} # Remove everything up to first /
Regular Expressions
# Pattern matching with [[ ]]
if [[ $string =~ ^[0-9]+$ ]]; then
echo "String contains only digits"
fi
# Extended globbing
shopt -s extglob
ls *.@(jpg|png|gif) # Files with jpg, png, or gif extensions
Command Line Shortcuts
# History expansion
!! # Last command
!n # Command number n
!string # Last command starting with string
^old^new # Replace old with new in last command
# Tab completion
# Press Tab to complete commands, filenames, variables
# Brace expansion
echo {1..10} # 1 2 3 4 5 6 7 8 9 10
echo {a..z} # a b c d ... z
mkdir dir{1,2,3} # Create dir1, dir2, dir3
Best Practices
Script Structure
#!/bin/bash
# Script: backup.sh
# Description: Backup important files
# Author: Your Name
# Date: 2024-01-01
set -euo pipefail # Exit on error, undefined variables, pipe failures
# Global variables
readonly BACKUP_DIR="/backup"
readonly LOG_FILE="/var/log/backup.log"
# Functions
log() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"
}
main() {
log "Starting backup process"
# Main logic here
log "Backup completed successfully"
}
# Check if running as root
if [[ $EUID -eq 0 ]]; then
echo "Don't run this script as root"
exit 1
fi
# Call main function
main "$@"
Error Handling
# Check command success
if ! command -v git &> /dev/null; then
echo "Git is not installed"
exit 1
fi
# Trap for cleanup
cleanup() {
echo "Cleaning up temporary files"
rm -f /tmp/tempfile*
}
trap cleanup EXIT
# Validate arguments
if [[ $# -lt 2 ]]; then
echo "Usage: $0 <source> <destination>"
exit 1
fi
Security Considerations
# Quote variables to prevent word splitting
cp "$file" "$destination"
# Use arrays for commands with spaces
command=("rsync" "-av" "--delete")
"${command[@]}" "$source/" "$destination/"
# Validate input
read -p "Enter filename: " filename
if [[ ! "$filename" =~ ^[a-zA-Z0-9._-]+$ ]]; then
echo "Invalid filename"
exit 1
fi
Common Pitfalls
Quoting Issues
# Wrong - word splitting occurs
for file in $(ls *.txt); do
echo $file
done
# Right - proper quoting
while IFS= read -r -d '' file; do
echo "$file"
done < <(find . -name "*.txt" -print0)
Variable Scope
# Global variable modified in subshell
counter=0
cat file.txt | while read line; do
((counter++))
done
echo $counter # Still 0!
# Solution: use process substitution
counter=0
while read line; do
((counter++))
done < <(cat file.txt)
echo $counter # Correct value
File Testing
# Wrong - doesn't handle spaces in filenames
if [ -f $file ]; then
# Right - proper quoting
if [[ -f "$file" ]]; then
Conclusion
Mastering Bash is a journey that pays dividends in productivity and system understanding. Start with the basics and gradually incorporate advanced features into your workflow. Practice regularly, read existing scripts, and don't hesitate to experiment in a safe environment.
Remember these key principles:
- Always quote your variables
- Use
set -euo pipefail
for robust scripts - Handle errors gracefully
- Write readable, well-commented code
- Test your scripts thoroughly
With these skills and practices, you'll be well on your way to becoming a Bash expert. The command line will transform from a intimidating interface into a powerful ally in your daily computing tasks.
And as always please feel free to criticize this article and share your thoughts! Cheers
Top comments (0)