Batch renaming tool written in Go language

Recently I created a file renaming tool using Go language. This tool is portable and even works on Windows.

You can install the tool with Homebrew

brew install itchyny/tap/mmv

or building with Go.

go get github.com/itchyny/mmv/cmd/mmv

You can use your own $EDITOR to rename multiple files at once.

The idea of renaming files using editor is not a new one.

I have been a big fan of renaming feature of vimfiler for long time. But recently I came up with creating an independent command line tool, targeting various users other than Vim users. Also, I was interested in the technological difficulties behind batch renaming.

Simple batch renaming can be implemented as follows.

func Rename(files map[string]string) error {
for src, dst := range files {
if err := os.Rename(src, dst); err != nil {
return err
}
}
return nil
}

But there are some troublesome cases. Firstly, cyclic case;

a => b
b => c
c => a

and secondly, slicing case;

a => b
b => c
c => d

These are rare cases in actual situation, but without considering these cases, it can lead to losing important files. We can choose two strategies;

  • detect these cases and return an error
  • implement renaming these cases

I had been thinking for which strategy to choose, but it’s not that difficult to list renaming tasks if I can implement detection for these cases.

So how can we rename for these cases? For cyclic case, use a temporary file;

a => tmp
c => a
b => c
tmp => b

and for slicing case, rename in the following order;

c => d
b => c
a => b

This is apparently a graph problem. We can detect the cycle by marking the visited nodes and for slicing case, we can rename from the leaf node.

Anyway, I know these cases unlikely happen in real use case. But user would probably swapping files when they swap the file names so I implemented. It is interesting that we solve a graph problem when we implement a batch renaming tool.

This tool is just a batch renaming tool. Opens an editor and read the file name changes and rename. One additional feature is to create the destination directory if not exist.

All the features I want are already implemented. I think I will not implement other difficult features for this tool. For example, file deletion feature or undo the renames. These features are too complex that I don’t want to maintain. And massren already implements these so those who wants these powerful features can use it.

Implementing no more features is one of the important design guidelines.

A software has more features, user have to learn more. Even if batch rename is rarely done in the first place, can we master the renaming tool when it has various features?

When creating an independent command line tool, try reducing features as much as possible. Adding features that are rarely used may create difficult impression for many people. When user think a tool difficult, they will gradually forget the tool.

It is difficult to keep a tool simple. Sometimes a famous engineer send you a feature request or pull request or you may be get down vote for a comment to reject the request. But it is you, yourself that maintain the code after accepting the patch. There may happen more requests for the accepted features or introduce various bugs and make it uncontrollable. It is sometimes important to reject the feature request when you think it too complex to maintain.

The ability to judge whether or not a feature request makes sense against the design guidelines of the software, and it leads to a survival strategy for maintaining OSS for a long time.

I creating a batch renaming tool with two features.

  • Edit file names with editor and rename by the result.
  • Create the destination if not exist and move the file.

I’m already satisfied and I think I use this simple tool actually. If I keep the design decision to keep the tool simple, even a year passes I will be able to remember all the features.

A programmer who loves programming languages.