CLI tool
ayoisaiah/f2 avatar
ayoisaiah/f2

F2: Batch Renaming Files and Directories from the Command Line

F2 is a cross-platform command-line tool for batch renaming files and directories quickly and safely. Written in Go!

2,452 stars65 forksGoMIT

At a glance

What is it?
F2 is a Go command-line tool for batch renaming files and directories, with dry runs by default, EXIF and ID3 variables, conflict detection and undo. Here is how it installs, what the mechanism actually is, and where it stops being the right tool.
Who is it for?
Adopt F2 when you rename in bulk on a shell and want a preview before anything moves: the dry run default and the undo record cover the two ways a bulk rename goes wrong. Skip it if your renames are one-off edits in a GUI, or if you need a library API rather than a binary, since the repository is a CLI project and the documentation describes it that way.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 7 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 1, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem F2 targets: shell renames that are hard to reverse

A loop over mv or rename works until it does not. The failure modes are predictable: two source names collapse onto the same target, a pattern matches one file more than intended, and the only record of the original names is your shell history. F2 is built around that gap. The README states that it defaults to a dry run so you can review the renaming changes before proceeding, and it lists undo functionality as a first-class feature: "Any renaming operation can be easily undone to allow the easy correction of mistakes." Those two choices define the audience. This is for people who already work in a terminal and rename in batches: photo libraries where the useful name lives in EXIF, music folders where it lives in ID3 tags, downloaded archives with inconsistent prefixes, or a directory of files that needs a numeric suffix. It is not aimed at someone renaming one file, and it is not a file manager. The repository is laid out as a Go CLI: cmd/ holds the entry point, with app/, find/, rename/, replace/, report/ and validate/ as separate packages. That split is visible in the top-level listing and it tells you the design is staged rather than a single pass over argv.

How F2 works: find, replace, validate, then rename

The package names describe the pipeline. find/ selects the files, replace/ computes the new names, validate/ runs the checks, rename/ performs the move, and report/ presents the result. The README frames the safety claim around that validation step: "Each renaming operation is validated before execution and detected conflicts can be automatically resolved." The dry run sits in front of the whole thing, so the default invocation computes the same mapping it would execute and shows it instead of moving anything. The variable system is what separates F2 from a plain regex renamer. The README states that F2 allows you to use file attributes, such as EXIF data for images or ID3 tags for audio files, to build new names. The go.mod confirms the machinery: github.com/rwcarlsen/goexif and github.com/barasher/go-exiftool for image metadata, github.com/dhowden/tag for audio tags, and gopkg.in/djherbis/times.v1 for timestamps. Two of those are worth flagging. go-exiftool is a wrapper that calls the external ExifTool binary, and the Dockerfile installs exiftool in the final image with apk add --no-cache exiftool, which is a strong hint that some metadata paths depend on it being present. If you install the binary alone and your rename rule reads EXIF fields, check whether ExifTool is on the machine first. The README also points to dedicated documentation pages for pair renaming, CSV-driven renaming and sorting, which suggests those are separate mechanisms rather than flags on the same code path.

Installing F2 and running a first rename

The README gives the Go route directly, requiring v1.23 or later:

bash
go install github.com/ayoisaiah/f2/v2/cmd/f2@latest

That places an f2 binary in your Go bin directory. For everyone else, the README says other installation methods are documented on the getting-started page, and points to the releases page for a pre-compiled binary for your operating system. There is also an npm package, @ayoisaiah/f2, whose package.json declares a postinstall script running go-npm install and a goBinary block naming the binary f2, with a download URL built from the release tag. Note the version in that file: 2.2.3, while the most recent tagged release listed is v2.2.2. Treat the npm package as a wrapper around a release download rather than a separate build. A Dockerfile is present too, building with Go 1.27.1 on Alpine and setting ENTRYPOINT ["f2"], with exiftool installed in the final stage.

Once installed, the workflow is preview, then execute. Run f2 with your rename rule and no execution flag, read the table of proposed names, and only then add the flag the documentation specifies for applying the change. The README does not spell out that flag in the text quoted here, so confirm it on the getting-started or tutorial page before your first real run. Two behaviours to verify on your own machine, because the README asserts them without a worked example in the excerpt: that the default really is a dry run in your installed version, and that the undo command reverses the last operation. Test both in a scratch directory with copies of files you can afford to lose.

Where F2 is the wrong tool

The dry run and the undo record cover renames that go through F2. They do not cover a rename you performed with mv, and the README does not document importing external history or reconstructing a mapping from a directory listing. If your renames happen across several tools, F2's undo only knows about its own operations. The second limit is metadata. Because the EXIF path leans on go-exiftool, a machine without ExifTool, or a file whose metadata is missing or malformed, changes what the variables resolve to, and a rename rule that assumes a capture date will produce empty or fallback segments on those files. The README does not document how missing metadata is handled, so treat that as an open question and test it against a file with stripped EXIF before running the rule across a library. Third, this is a CLI with a large option surface. The README advertises "a full range of renaming capabilities" spanning string replacements and regular expressions, and the repository carries a validate package and a dedicated conflict-detection guide. That breadth is the point, but it means a complex rule is something you build and check incrementally, not something you guess at. If your rename needs are a handful of files a year, a file manager's rename dialog is faster than learning the variable syntax.

F2 against the rename and mv one-liners you already use

The obvious alternative is the util-linux rename command or a shell loop over mv. The difference is not speed, it is what happens before and after. A shell loop applies changes as it goes; if the fifth of fifty files collides with an existing name, you have a partially renamed directory and no record of the first four. F2's approach is to compute the full mapping first, validate it as a set, and only then move files, which is why conflict detection can be discussed as a feature rather than a caveat. The second alternative is a scripted rename in Python or Go. That gives you unlimited control, and it is the right answer when the naming logic depends on something outside the filesystem, such as a database or an API. What you give up is the parts F2 already built: the dry run, the conflict checks, the undo record, and the metadata variables for EXIF and ID3. Writing those yourself is a few hundred lines you then have to maintain. A third option is a GUI batch renamer, which is easier to learn but harder to put in a script or a container. F2's Dockerfile and its packaged binary make it something you can run in a pipeline, which a desktop renamer is not.

Maintenance, licence and the upgrade path

F2 is MIT licensed, stated in the README and in the LICENCE file, and the Dockerfile carries the label org.opencontainers.image.licenses="MIT". MIT is permissive: you can use the binary in commercial work and in internal tooling, and you can fork it. It comes with no warranty, and the licence file is the authority rather than this summary. On activity, the repository is not archived, and the last push was on 2026-09-24, four days before this writing, with a nightly build published the same day. The most recent tagged release listed is v2.2.2 from 2025-11-10, so the tagged cadence is slower than the commit cadence, and the nightly channel is where master currently lands. Upgrading is cheap if you installed via go install, since the command is versioned and you rerun it to move forward. If you installed the npm wrapper, the version you get is pinned by the package, and the package.json here reads 2.2.3 while the newest tagged release is v2.2.2, so check which binary you actually received. The dependency list is ordinary for a Go CLI: urfave/cli for flags, pterm for output, go-i18n for the translated READMEs. Nothing there implies a heavy upgrade burden, but the go-exiftool dependency does mean the runtime environment matters as much as the Go version.

Editorial conclusion

Adopt F2 when you rename in bulk on a shell and want a preview before anything moves: the dry run default and the undo record cover the two ways a bulk rename goes wrong. Skip it if your renames are one-off edits in a GUI, or if you need a library API rather than a binary, since the repository is a CLI project and the documentation describes it that way. Before trusting it on a large tree, run one rename in a scratch directory, confirm the preview matches what you expect, then check that f2 undo restores the original names, because undo is the feature you will need exactly once and only after you have already made the mistake.

Frequently asked questions

How do I install F2 on my machine?

Go developers can run go install github.com/ayoisaiah/f2/v2/cmd/f2@latest, which requires Go v1.23 or later. The README says other installation methods are documented on the getting-started page, and pre-compiled binaries for each operating system are on the releases page.

Does F2 rename files immediately when I run it?

No. The README states that F2 defaults to a dry run so you can review the renaming changes before proceeding. You inspect the proposed names, then apply the change with the execution flag documented in the getting-started guide.

Can F2 undo a batch rename if I make a mistake?

The README lists undo functionality as a feature and says any renaming operation can be easily undone. The undo history covers operations performed by F2 itself, not renames you carried out with other tools.

Official sources

  1. ayoisaiah/f2 on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/ayoisaiah-f2.svg)](https://hysenlabs.com/projects/ayoisaiah-f2)