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()andreaddir()to read directories - How to use
stat()to detect files vs directories - Recursive directory traversal
- Memory management with
strdup()andfree() - 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:
- Read directory entries using
readdir() - Store them in an array
- Sort them using
qsort() - Filter based on flags (
-d) - Print with proper indentation
- 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.