/usr/bin/filter


Replacing mv

Filter uses regular expressions to rename files. I have always felt this is the “missing UNIX command”:

$ filter report* "s/..from.chris.//"

report analysis (from chris).doc     ->     report analysis.doc
report datasheet (from chris).xls    ->     report datasheet.xls
report discussion (from chris).doc   ->     report discussion.doc
Rename these files? [y/N]
$ filter * "s/Episode./S01E0/"

Game of Thrones Episode 1.mpg    ->     Game of Thrones S01E01.mpg
Game of Thrones Episode 2.mpg    ->     Game of Thrones S01E02.mpg
Game of Thrones Episode 3.mpg    ->     Game of Thrones S01E03.mpg
Rename these files? [y/N]

Usage

filter wraps around GNU sed, so it uses s/search/replace syntax. For example, to rename all .txt files, changing the a’s to e’s:

$ filter *.txt s/a/e/

The syntax also supports backreferences, which are captured in brackets. Refer to groups with \1, \2 etc.

$ filter * "s/foo\(.\)bar/baz\1/"

foo1bar.txt    ->     baz1.txt
foo2bar.txt    ->     baz2.txt
foo3bar.txt    ->     baz3.txt
Rename these files? [y/N]

Why?

filter is just a small script, but it solves a frustrating problem. Every time I’m in this situation I consult Google and come across gems like:

  • find . -exec echoecho “{}” | sed ’s/./foo/g’\;
  • ls F00001-0708-*|sed 's/\(.\).\(.*\)/mv & \1\2/' | sh
  • for i in *; do ; mv "$i" "echo $i | sed “s/(.) - (.) - (.) - (.).ogg/\1 - \4 - \3 - \2.ogg/”"; done

I hope that you like my solution better.