🌳 Building `ctree`: A Lightweight Unix `tree` Clone in C

When I started learning low-level programming, I wanted to build something practical — not just theory. So I decided to recreate a simplified version of the Unix tree command using C.

This project, called ctree, helped me deeply understand filesystem traversal, recursion, and how real CLI tools work under the hood.

🔗 Source Code

👉 Check out the full project on GitHub:

🚀 What is ctree?

ctree is a lightweight command-line tool that prints directory structures in a tree-like format — just like the Unix tree utility.

But instead of using an existing tool, I built it from scratch using pure C and POSIX APIs.

🧠 What I Learned

This project was more than just printing directories. It taught me:

  • How to use opendir() and readdir() to read directories
  • How to use stat() to detect files vs directories
  • Recursive directory traversal
  • Memory management with strdup() and free()
  • Sorting using qsort()
  • Building CLI tools with argument parsing
  • Designing modular C projects (header + source + main)

✨ Features

Here’s what ctree can do:

📂 Tree Structure

Prints directories and files in a clean tree format:

.
|-- main.c
|-- src
|   L__ utils.c
L__ include

🔢 Count Summary

Shows total directories and files:

3 directories, 2 files

📁 -d (Directories Only)

./ctree -d

➡️ Shows only directories (no files)

📏 -L (Depth Limit)

./ctree -L 2

➡️ Limits how deep the recursion goes

🔤 Sorted Output

Entries are sorted alphabetically using qsort() for clean output.

📦 File Sizes

Files display their size:

main.c (1200 bytes)

🏗 Project Structure

ctree/
├── Tree.h
├── Tree.c
└── main.c
  • Tree.h → declarations and configuration
  • Tree.c → core logic (recursion, sorting, filtering)
  • main.c → CLI argument parsing

⚙️ How It Works

The core logic follows a simple but powerful pipeline:

  1. Read directory entries using readdir()
  2. Store them in an array
  3. Sort them using qsort()
  4. Filter based on flags (-d)
  5. Print with proper indentation
  6. Recursively process subdirectories

This pattern is actually similar to how real CLI tools are implemented.

🔧 Compilation & Usage

Compile:

gcc Tree.c main.c -o ctree

Run:

./ctree

Examples:

./ctree -d
./ctree -L 2
./ctree -d -L 2
./ctree /some/path

⚠️ Challenges I Faced

One tricky bug I encountered was incorrect tree formatting when using the -d flag.

Because I filtered files after counting entries, the program misidentified the “last” element in a directory.

✅ Solution:

I fixed it by:

  • First collecting entries
  • Then filtering them
  • Then printing with correct indexing

This small change made the output accurate and robust.

📈 What’s Next?

I’m planning to improve ctree with:

  • 🎨 Colored output (like real tree)
  • 👁 Support for hidden files (-a)
  • 📊 Human-readable file sizes (KB, MB)
  • ⚡ Performance optimizations

💬 Final Thoughts

Building ctree was a huge step for me in understanding how system-level tools work.

It’s easy to use commands like tree every day — but building one yourself changes how you see the system.

If you’re learning C, I highly recommend building small CLI tools like this. You’ll learn way more than from tutorials alone.