Part 5: Challenge Solutions & Next Steps

  1. Tutorial Index
  2. Part-00 : Setup
  3. Part-01 : Getting Started
  4. Part-02 : Reading and Searching
  5. Part-03 : Permissions and Processes
  6. Part-04 : Environment Customization
  7. Part-05 : Solutions and Next Steps ◄ You are here

Try First, Then Learn

These are complete solutions to all workshop challenges. Make sure you’ve attempted each challenge on your own before looking at the solutions. The learning happens in the struggle!


Part 1 Solution: Build a Project Structure

The Challenge

Create this directory structure:

~/workshop-challenges/web-project/
├── src/
│   ├── components/
│   │   ├── Header.js
│   │   └── Footer.js
│   └── styles/
│       └── main.css
├── public/
│   └── index.html
├── tests/
│   └── app.test.js
└── README.md

Complete Solution

Approach 1: Step-by-step

# Start from home directory
cd ~

# Create root directory
mkdir -p workshop-challenges/web-project
cd workshop-challenges/web-project

# Create all directories
mkdir -p src/components
mkdir -p src/styles
mkdir public
mkdir tests

# Create files
touch src/components/Header.js
touch src/components/Footer.js
touch src/styles/main.css
touch public/index.html
touch tests/app.test.js
touch README.md

# Verify
ls -R

Approach 2: Efficient (one-liner approach)

cd ~ && \
mkdir -p workshop-challenges/web-project/{src/{components,styles},public,tests} && \
cd workshop-challenges/web-project && \
touch src/components/{Header,Footer}.js src/styles/main.css public/index.html tests/app.test.js README.md

Approach 3: Using brace expansion

cd ~
mkdir -p workshop-challenges/web-project
cd workshop-challenges/web-project

# Create directories with brace expansion
mkdir -p src/{components,styles} public tests

# Create files with brace expansion
touch src/components/{Header,Footer}.js
touch src/styles/main.css
touch public/index.html
touch tests/app.test.js
touch README.md

What You Learned

  • Using mkdir -p to create nested directories
  • Brace expansion {a,b,c} for efficiency
  • Creating multiple files with touch
  • Directory navigation with cd

Common Mistakes

Mistake 1: Forgetting -p flag

mkdir src/components  # Error if src doesn't exist
mkdir -p src/components  # Creates parent directories

Mistake 2: Wrong location

# Make sure you're in the right place
pwd  # Check current directory
cd ~/workshop-challenges/web-project  # Go to correct location

Part 2 Solution: Web Server Log Analysis

The Challenge

Analyze sample-data/server.log and answer 5 questions.

Complete Solution

Question 1: How many total requests?

wc -l sample-data/server.log
# Output: 8 sample-data/server.log

# Or just the number:
wc -l < sample-data/server.log
# Output: 8

Question 2: How many 404 errors?

grep "404" sample-data/server.log | wc -l
# Output: 2

# Alternative:
grep -c "404" sample-data/server.log
# Output: 2

Question 3: List all unique IP addresses

cut -d' ' -f1 sample-data/server.log | sort -u
# Output:
# 192.168.1.1
# 192.168.1.2
# 192.168.1.3
# 192.168.1.4

# To count them:
cut -d' ' -f1 sample-data/server.log | sort -u | wc -l
# Output: 4

Question 4: Which IP made the most requests?

cut -d' ' -f1 sample-data/server.log | sort | uniq -c | sort -rn | head -1
# Output: 4 192.168.1.1

# More readable format:
cut -d' ' -f1 sample-data/server.log | sort | uniq -c | sort -rn | head -1 | awk '{print $2 " (" $1 " requests)"}'
# Output: 192.168.1.1 (4 requests)

Question 5: Show only successful requests (HTTP 200)

grep " 200 " sample-data/server.log
# Output: All lines with status 200

# Count them:
grep -c " 200 " sample-data/server.log
# Output: 5

Complete answers.txt File

# Create answers.txt
cat > ~/answers.txt << 'EOF'
Question 1: Total requests
Command: wc -l sample-data/server.log
Output: 8

Question 2: 404 errors
Command: grep -c "404" sample-data/server.log
Output: 2

Question 3: Unique IPs
Command: cut -d' ' -f1 sample-data/server.log | sort -u
Output:
192.168.1.1
192.168.1.2
192.168.1.3
192.168.1.4

Question 4: Most active IP
Command: cut -d' ' -f1 sample-data/server.log | sort | uniq -c | sort -rn | head -1
Output: 192.168.1.1 (4 requests)

Question 5: Successful requests
Command: grep " 200 " sample-data/server.log
Output: 5 lines with status 200
EOF

Explanation of Commands

cut -d' ' -f1

  • -d' ': Use space as delimiter
  • -f1: Extract first field (the IP address)

sort | uniq -c

  • sort: Sort lines (required for uniq)
  • uniq -c: Count unique occurrences

sort -rn

  • -r: Reverse (highest first)
  • -n: Numeric sort

head -1

  • Show only the first line (the highest count)

Alternative Solutions

Using awk for Question 4:

awk '{print $1}' sample-data/server.log | sort | uniq -c | sort -rn | head -1

Using grep -o for IP extraction:

grep -oE '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' sample-data/server.log | sort | uniq -c

What You Learned

  • Extracting columns with cut
  • Counting occurrences with uniq -c
  • Sorting numerically with sort -n
  • Chaining commands with pipes
  • Pattern matching with grep

Part 3 Solution: Script Setup & Execution

The Challenge

  1. Make hello.sh executable (only for you)
  2. Make backup.sh readable and executable by everyone
  3. Make secret.sh readable and writable only by you
  4. Create sysinfo.sh that displays system information
  5. Make sysinfo.sh executable

Complete Solution

Step 1: Set permissions for hello.sh

cd ~/scripts
chmod 700 hello.sh

# Verify
ls -l hello.sh
# Output: -rwx------ ... hello.sh

Step 2: Set permissions for backup.sh

chmod 755 backup.sh

# Verify
ls -l backup.sh
# Output: -rwxr-xr-x ... backup.sh

Step 3: Set permissions for secret.sh

chmod 600 secret.sh

# Verify
ls -l secret.sh
# Output: -rw------- ... secret.sh

Step 4: Create sysinfo.sh

cat > ~/scripts/sysinfo.sh << 'EOF'
#!/bin/bash

echo "System Information"
echo "=================="
echo ""
echo "Date and Time:"
date
echo ""
echo "Username:"
whoami
echo ""
echo "Current Directory:"
pwd
EOF

Alternative sysinfo.sh with better formatting:

cat > ~/scripts/sysinfo.sh << 'EOF'
#!/bin/bash

echo "================================"
echo "    System Information"
echo "================================"
echo ""
echo "Date/Time: $(date)"
echo "User:      $(whoami)"
echo "Directory: $(pwd)"
echo "Hostname:  $(hostname)"
echo "Shell:     $SHELL"
echo ""
echo "================================"
EOF

Step 5: Make sysinfo.sh executable

chmod +x ~/scripts/sysinfo.sh

# Verify
ls -l ~/scripts/sysinfo.sh
# Output: -rwxr-xr-x ... sysinfo.sh

Test it:

~/scripts/sysinfo.sh
# Or if ~/scripts is in PATH:
sysinfo.sh

Understanding Permissions

Permission number breakdown:

rwx rwx rwx  = 777
421 421 421

Owner Group Others

Common combinations:

  • 700 = rwx—— (Only owner has full access)
  • 755 = rwxr-xr-x (Owner full, others read+execute)
  • 644 = rw-r–r– (Owner read+write, others read only)
  • 600 = rw—–– (Only owner read+write)
  • 400 = r–––– (Only owner read, cannot modify)

Alternative Permission Methods

Using symbolic notation:

# hello.sh - only user executable
chmod u=rwx,g=,o= hello.sh
# Or:
chmod u+rwx,g-rwx,o-rwx hello.sh

# backup.sh - everyone can read and execute
chmod u=rwx,g=rx,o=rx backup.sh
# Or:
chmod a+rx backup.sh

# secret.sh - only user read/write
chmod u=rw,g=,o= secret.sh

What You Learned

  • Setting permissions with numbers (octal notation)
  • Setting permissions with symbols (symbolic notation)
  • Understanding owner, group, and others
  • Making scripts executable
  • Creating scripts with heredoc (<<)

Common Mistakes

Mistake 1: Forgetting the shebang

# Wrong:
echo "date" > script.sh

# Correct:
echo "#!/bin/bash" > script.sh
echo "date" >> script.sh

Mistake 2: Wrong permission order

# Remember: owner, group, others
chmod 700 file  # owner=7, group=0, others=0

Part 4 Solution: Environment Customization

The Challenge

  1. Add 5 required aliases to your shell config
  2. Add the mkcd function
  3. Reload configuration
  4. Test everything works

Complete Solution

Step 1: Backup your config

cp ~/.bashrc ~/.bashrc.backup
# Or for zsh:
cp ~/.zshrc ~/.zshrc.backup

Step 2: Add aliases and function

# Open your config file
nano ~/.bashrc  # or ~/.zshrc

# Scroll to the end and add:
# Workshop Aliases
alias ll='ls -lah'
alias gs='git status'
alias gp='git pull'
alias dev='cd ~/workshop-challenges'
alias reload='source ~/.bashrc'  # Change to ~/.zshrc if using zsh

# Create directory and enter it
mkcd() {
    mkdir -p "$1" && cd "$1"
}

Step 3: Save and reload

In nano: Ctrl+O, Enter, Ctrl+X

source ~/.bashrc
# Or for zsh:
source ~/.zshrc

Step 4: Test everything

# Test ll
cd ~
ll
# Should show detailed listing

# Test gs
gs
# Should show git status or error if not in git repo

# Test dev
dev
pwd
# Should show: /home/yourusername/workshop-challenges

# Test mkcd
cd ~
mkcd test-directory
pwd
# Should show: /home/yourusername/test-directory

# Test reload
echo "alias test='echo works'" >> ~/.bashrc
reload
test
# Should output: works

Complete .bashrc Addition

Here’s a complete section to add to your .bashrc:

# =====================================
# Workshop Customizations
# =====================================

# Required aliases
alias ll='ls -lah'
alias gs='git status'
alias gp='git pull'
alias dev='cd ~/workshop-challenges'

# Determine which config file to reload
if [ -n "$BASH_VERSION" ]; then
    alias reload='source ~/.bashrc'
elif [ -n "$ZSH_VERSION" ]; then
    alias reload='source ~/.zshrc'
fi

# Useful function: make directory and change into it
mkcd() {
    if [ -z "$1" ]; then
        echo "Usage: mkcd <directory>"
        return 1
    fi
    mkdir -p "$1" && cd "$1"
}

# =====================================
# End Workshop Customizations
# =====================================

Bonus: Additional Useful Customizations

# Navigation
alias ..='cd ..'
alias ...='cd ../..'
alias ....='cd ../../..'
alias ~='cd ~'
alias -- -='cd -'  # Go to previous directory

# Listing variations
alias la='ls -A'
alias l='ls -CF'
alias lt='ls -ltrh'  # Sort by time, newest last
alias lsize='ls -lSrh'  # Sort by size

# Safety nets
alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'
alias ln='ln -i'

# Git shortcuts
alias ga='git add'
alias gc='git commit'
alias gco='git checkout'
alias gb='git branch'
alias gl='git log --oneline --graph'
alias gd='git diff'

# System info
alias df='df -h'
alias du='du -h'
alias free='free -h'
alias ps='ps auxf'
alias psg='ps aux | grep -v grep | grep -i -e VSZ -e'

# Quick edits
alias bashrc='nano ~/.bashrc'
alias zshrc='nano ~/.zshrc'
alias hosts='sudo nano /etc/hosts'

# Networking
alias ports='netstat -tulanp'
alias myip='curl ifconfig.me'
alias pingg='ping google.com'

# Utility functions
extract() {
    if [ -f "$1" ]; then
        case "$1" in
            *.tar.bz2)   tar xjf "$1"   ;;
            *.tar.gz)    tar xzf "$1"   ;;
            *.bz2)       bunzip2 "$1"   ;;
            *.rar)       unrar x "$1"   ;;
            *.gz)        gunzip "$1"    ;;
            *.tar)       tar xf "$1"    ;;
            *.tbz2)      tar xjf "$1"   ;;
            *.tgz)       tar xzf "$1"   ;;
            *.zip)       unzip "$1"     ;;
            *.Z)         uncompress "$1";;
            *.7z)        7z x "$1"      ;;
            *)           echo "'$1' cannot be extracted" ;;
        esac
    else
        echo "'$1' is not a valid file"
    fi
}

# Create backup of file
backup() {
    cp "$1" "$1.backup-$(date +%Y%m%d-%H%M%S)"
    echo "Backed up $1"
}

# Find process by name
psgrep() {
    ps aux | grep -v grep | grep -i -e VSZ -e "$1"
}

# Make directory and create .gitkeep
mkgit() {
    mkdir -p "$1" && touch "$1/.gitkeep" && cd "$1"
}

What You Learned

  • Editing shell configuration files
  • Creating persistent aliases
  • Writing shell functions
  • Reloading configuration without restarting
  • Difference between .bashrc and .zshrc

Common Issues and Fixes

Issue 1: Changes don’t persist

# Make sure you're editing the right file
echo $SHELL  # Check your shell

# For bash:
nano ~/.bashrc

# For zsh:
nano ~/.zshrc

Issue 2: Aliases don’t work in scripts

# Aliases only work in interactive shells
# Use functions instead for scripts:

# In script (functions work):
mkcd() { mkdir -p "$1" && cd "$1"; }
mkcd test

# Not in script (aliases don't work):
alias mkcd='mkdir -p "$1" && cd "$1"'  # Won't work in script

Issue 3: mkcd doesn’t work

# Make sure function syntax is correct:
mkcd() {
    mkdir -p "$1" && cd "$1"
}

# Not:
function mkcd() {  # This works but is bash-specific
    mkdir -p "$1" && cd "$1"
}

Verification

To verify all your solutions work:

# Clone the workshop repo
git clone https://github.com/yourusername/linux-tutorial.git
cd linux-tutorial

# Run all verifications
cd 01-getting-started && ./verify.sh
cd ../02-reading-searching && ./verify.sh
cd ../03-permissions-processes && ./verify.sh
cd ../04-environment-customization && ./verify.sh

What’s Next?

Congratulations on completing the workshop! Here’s your path forward:

Immediate Practice (This Week)

  1. Daily Usage: Use the terminal for everyday tasks

    • Navigate your filesystem
    • Create and organize project files
    • Check git status and logs
    • Search through files
  2. OverTheWire Bandit: Complete levels 0-15

  3. Customize Further:

    • Add 10 more aliases for your workflow
    • Create 3 custom functions you’ll actually use
    • Install and configure a tool you find interesting

Deepen Your Skills (Next Month)

  1. Bash Scripting:

  2. Text Processing Masters:

    • Learn sed for find-and-replace
    • Master awk for data processing
    • Understand regular expressions
  3. Version Control:

    • Deep dive into Git
    • Learn branching and merging
    • Contribute to open source

Advanced Topics (2-3 Months)

  1. Multiplexing: tmux or screen

    • Multiple terminal sessions
    • Persistent remote sessions
  2. Editor Mastery: Choose one

    • Vim: Modal editing, incredibly powerful
    • Neovim: Modern Vim with Lua config
    • Emacs: Extensible, full environment
  3. Remote Work:

    • SSH: Secure shell access
    • SCP/RSYNC: File transfer
    • SSH keys and config
  4. Systems Administration:

    • systemd: Service management
    • cron: Task scheduling
    • Log management with journalctl
  5. Modern Tools:

    • fzf: Fuzzy finder
    • ripgrep: Better grep
    • bat: Better cat
    • exa: Modern ls
    • zoxide: Smart cd

Practice Resources

Interactive Learning:

Documentation:

Communities:


Final Thoughts

The command line is not about memorizing commands. It’s about:

  1. Understanding concepts: Pipes, redirection, permissions, processes
  2. Knowing what’s possible: You can always look up syntax
  3. Building intuition: Practice makes patterns obvious
  4. Creating your workflow: Customize to match how you think

Remember: Even experienced developers:

  • Google syntax regularly
  • Check man pages constantly
  • Look up examples online
  • Copy and modify existing scripts

The difference is they know what to search for and what’s possible.


Keep Learning

The skills you’ve learned will serve you throughout your career. Every time you:

  • Deploy to a server
  • Debug a production issue
  • Automate a boring task
  • Process large datasets
  • Work with Git
  • Configure your development environment

You’ll use these command-line skills.

Keep practicing. Keep exploring. Keep building.


Share Your Progress

Completed the workshop? Share it!

  • Make a linkedIn post and tag Open Source Chandigarh
  • Share your custom .bashrc configurations
  • Help others in the comments
  • Contribute to the workshop repository

You're Now a Command-Line User!

You’ve graduated from beginner to capable terminal user. The terminal is no longer intimidating - it’s your powerful tool. Keep practicing, keep customizing, and most importantly - have fun automating things!


Questions or Feedback?

Drop a comment below or reach out:

  • Workshop discussions
  • Suggestions for improvement
  • Your success stories

Happy hacking!