Rust is one of the best languages for building command-line tools. It compiles to fast native binaries, has a helpful compiler, and its ownership model guarantees memory safety without a garbage collector. I spent a weekend building a file organizer CLI in Rust, and this is what I learned.
The Idea
My Downloads folder was a disaster. Screenshots mixed with PDFs mixed with random `.zip` files from months ago. I wanted a tool that would sort files into subdirectories by type (images, documents, archives, code) and optionally by date.
use std::fs;
use std::path::Path;
fn categorize(extension: &str) -> &str {
match extension {
"jpg" | "png" | "gif" | "webp" | "svg" => "images",
"pdf" | "doc" | "docx" | "txt" | "md" => "documents",
"zip" | "tar" | "gz" | "rar" => "archives",
"rs" | "ts" | "js" | "py" | "go" => "code",
_ => "other",
}
}
fn organize_directory(dir: &Path) -> std::io::Result<u32> {
let mut count = 0;
for entry in fs::read_dir(dir)? {
let entry = entry?;
let path = entry.path();
if path.is_file() {
let ext = path.extension()
.and_then(|e| e.to_str())
.unwrap_or("other");
let category = categorize(ext);
let target_dir = dir.join(category);
fs::create_dir_all(&target_dir)?;
fs::rename(&path, target_dir.join(entry.file_name()))?;
count += 1;
}
}
Ok(count)
}
The Rust compiler is famously strict, and it lived up to its reputation. My first attempt had about fifteen errors, mostly around ownership and borrowing. But every single error message was *helpful*. The compiler did not just tell me what was wrong; it told me *why* and often suggested a fix.
What I Learned About Rust
**Pattern matching is incredible.** Coming from JavaScript's `switch` statements, Rust's `match` feels like a superpower. It is exhaustive by default: if you forget a case, the compiler tells you.
**The ownership model makes sense once it clicks.** For the first hour, I was fighting the borrow checker. By the second hour, I started understanding *why* it was stopping me. By the end of the weekend, I was writing code that passed on the first try.
**Error handling is elegant.** The `Result` type and `?` operator make error propagation clean and explicit. No more try-catch pyramids.
Publishing and Sharing
I published the tool on GitHub and it has already gotten a few stars. Cargo, Rust's package manager, makes publishing straightforward. More importantly, I learned something new and had fun doing it. That is what side projects are for.
Key Takeaways
- Rust is an excellent choice for CLI tools due to fast native binaries and memory safety - The Rust compiler's error messages are unusually helpful and often suggest fixes - Pattern matching with `match` is exhaustive by default, catching missed cases at compile time - The ownership and borrowing model prevents memory bugs without a garbage collector - The `Result` type and `?` operator make error handling clean and explicit - Side projects are the best way to learn a new language because you have a concrete goal - Cargo makes publishing and sharing Rust tools simple