I had a shell script. It walked a directory of photos, read EXIF dates, and renamed and filed them into YYYY/MM folders. Forty lines of bash, a couple of exiftool calls, some awk I'd be embarrassed to show you. It worked. It also broke quietly the moment a filename had a space in it, and I'd patched that bug roughly three times because each fix forgot a different code path.
So I rewrote it in Rust. The honest question is whether that was a sensible use of a Wednesday evening, and I want to actually answer it rather than wave my hands.
The good first. The compiled binary does the same job in a fraction of the time, though for a few hundred photos that difference is academic, I'm not pretending otherwise. The real win is that the failure modes are now explicit. Where bash silently carried on after a failed command, the Rust version makes me handle the error or say ? and bail. Spaces in filenames, missing EXIF tags, two photos that want the same destination name: all of those are now things I had to think about, because the type system wouldn't let me not think about them.
The crate ecosystem did the heavy lifting. clap for argument parsing with derive, so the help text writes itself. walkdir for the recursion. kamadak-exif for reading the tags. The whole thing is maybe 180 lines and most of it reads like a description of what I want rather than how to coax the shell into doing it.
#[derive(Parser)]
struct Args {
/// Source directory of photos
source: PathBuf,
/// Where to file them
dest: PathBuf,
/// Print what would happen without moving anything
#[arg(long)]
dry_run: bool,
}
That --dry-run flag is the bit I'm proudest of, and it's the bit that would have been most annoying to bolt onto the bash version. In Rust it was a single if args.dry_run around the rename call.
Now the cost. It took me about three hours including the inevitable fight with lifetimes on a string I was borrowing in two places. The bash script took twenty minutes to write originally. So on pure time-to-first-working-version, bash won by an order of magnitude, and anyone who tells you Rust is just as quick for a throwaway script is selling something.
Was it worth it? For this script, genuinely yes, but not because of speed. It's worth it because I'll run this thing for years and I now trust it. The errors are loud, the binary is a single file I can drop on any machine, and there's no hidden dependency on whichever exiftool version happens to be installed. The bash script was faster to write and would have cost me an hour a year forever in mysterious breakages.
The rule I've landed on: if it's truly throwaway, keep it in bash. If I'm going to depend on it, the Rust tax buys me a tool I stop having to think about. That's the trade, plainly stated, and this time it came out ahead.