F2 Tutorial
Below is a detailed guide to using F2 for a variety of renaming tasks.
Important Note for Windows Users
- Always use double quotes (") when passing arguments to any flag in Command Prompt (CMD).
- PowerShell users may use single or double quotes.
General Usage
f2 FLAGS [OPTIONS] [PATHS TO FILES OR DIRECTORIES...]
Things to Note
- You must provide one of the
-f
,-u
,-r
, or--csv
flags to perform an operation. - If no paths are provided, F2 will default to searching the current directory.
- You can provide multiple paths, which can be absolute or relative, to specify files or directories.
f2 -f 'a' -r 'b' path/to/dir path/to/file.txt
- Hidden files are excluded by default unless you specify
-H
to include them. - F2 runs in dry-run mode by default. You must use
-x/--exec
to apply the changes.
Basic Find and Replace
f2 -f '[ ]{1,}' -r '_'
Output:
┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
| ORIGINAL | RENAMED | STATUS |
| ************************************************************************************************************** |
| Screenshot from 2022-04-12 14:37:35.png | Screenshot_from_2022-04-12_14:37:35.png | ok |
| Screenshot from 2022-04-12 15:58:55.png | Screenshot_from_2022-04-12_15:58:55.png | ok |
| Screenshot from 2022-06-03 11:29:16.png | Screenshot_from_2022-06-03_11:29:16.png | ok |
| Screenshot from 2022-09-26 21:19:15.png | Screenshot_from_2022-09-26_21:19:15.png | ok |
└────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
Arguments to -f
are treated as regular expressions by default. When you need to rename files containing regex special characters (such as . + ? ^ { } and others), you may escape the characters by prefixing them with a backslash:
f2 -f '\(2021\)' -r '[2022]'
Output:
┌──────────────────────────────────────────────────────────────────────────────────────┐
| ORIGINAL | RENAMED | STATUS |
| ************************************************************************************ |
| No Pressure (2021) S01.E01.2160p.mp4 | No Pressure [2022] S01.E01.2160p.mp4 | ok |
| No Pressure (2021) S01.E02.2160p.mp4 | No Pressure [2022] S01.E02.2160p.mp4 | ok |
| No Pressure (2021) S01.E03.2160p.mp4 | No Pressure [2022] S01.E03.2160p.mp4 | ok |
└──────────────────────────────────────────────────────────────────────────────────────┘
Or treat the search string as a literal using -s
:
f2 -f '(2021)' -r '[2022]' -s
Output:
┌──────────────────────────────────────────────────────────────────────────────────────┐
| ORIGINAL | RENAMED | STATUS |
| ************************************************************************************ |
| No Pressure (2021) S01.E01.2160p.mp4 | No Pressure [2022] S01.E01.2160p.mp4 | ok |
| No Pressure (2021) S01.E02.2160p.mp4 | No Pressure [2022] S01.E02.2160p.mp4 | ok |
| No Pressure (2021) S01.E03.2160p.mp4 | No Pressure [2022] S01.E03.2160p.mp4 | ok |
└──────────────────────────────────────────────────────────────────────────────────────┘
f2 -f '(2021)' -r '[2022]' -s
Limiting the Number of Replacements
By default, F2 replaces all matches in a filename. However, there are times when you might want to limit the number of replacements, and for this, the -l/--replace-limit
option can be used.
To replace only the first occurrence of a match in each filename, use:
f2 -f 'abc' -r '123' -l 1
Output:
┌────────────────────────────────────────────┐
| ORIGINAL | RENAMED | STATUS |
| ****************************************** |
| abc.txt | 123.txt | ok |
| abc_abc.txt | 123_abc.txt | ok |
| abc_abc_abc.txt | 123_abc_abc.txt | ok |
└────────────────────────────────────────────┘
In this example, only one occurrence of abc
is replaced in each filename.
You can also replace from the end of the file with a negative number:
f2 -f 'abc' -r '123' -l -1
Output:
┌────────────────────────────────────────────┐
| ORIGINAL | RENAMED | STATUS |
| ****************************************** |
| abc.txt | 123.txt | ok |
| abc_abc.txt | 123_abc.txt | ok |
| abc_abc_abc.txt | abc_abc_123.txt | ok |
└────────────────────────────────────────────┘
Renaming Files Recursively
To rename files recursively in a directory and all its subdirectories, use the -R/--recursive
option. This allows F2 to search through all levels of directories without imposing a depth limit unless specified otherwise.
Here's an example that replaces all instances of js
to ts
in the current directory and all sub directories.
f2 -f 'js' -r 'ts' -R
Output:
┌────────────────────────────────────────────────────┐
| ORIGINAL | RENAMED | STATUS |
| ************************************************** |
| index-01.js | index-01.ts | ok |
| index-02.js | index-02.ts | ok |
| one/index-03.js | one/index-03.ts | ok |
| one/index-04.js | one/index-04.ts | ok |
| one/two/index-05.js | one/two/index-05.ts | ok |
| one/two/index-06.js | one/two/index-06.ts | ok |
└────────────────────────────────────────────────────┘
You can control how many levels of subdirectories F2 searches by using the -m/--max-depth
option. For example, to limit the renaming operation to the first level of subdirectories:
f2 -f 'js' -r 'ts' -R -m 1
Output:
┌────────────────────────────────────────────┐
| ORIGINAL | RENAMED | STATUS |
| ****************************************** |
| index-01.js | index-01.ts | ok |
| index-02.js | index-02.ts | ok |
| one/index-03.js | one/index-03.ts | ok |
| one/index-04.js | one/index-04.ts | ok |
└────────────────────────────────────────────┘
You can also use the --exclude-dir
option to prevent recursing into a specific directory.
Renaming Directories
Directories are exempted from the renaming operation by default. Use the -d/--include-dir
flag to include them.
Original tree:
.
├── pic1.jpg
├── pic2.png
└── pics
├── pic3.webp
└── pic4.avif
f2 -f 'pic' -r 'image'
Notice that the pics
directory is exempt here:
┌────────────────────────────────┐
| ORIGINAL | RENAMED | STATUS |
| ****************************** |
| pic1.jpg | image1.jpg | ok |
| pic2.png | image2.png | ok |
└────────────────────────────────┘
It is included when you add the -d
flag:
f2 -f 'pic' -r 'image' -d
Output:
┌────────────────────────────────┐
| ORIGINAL | RENAMED | STATUS |
| ****************************** |
| pic2.png | image2.png | ok |
| pic1.jpg | image1.jpg | ok |
| pics | images | ok |
└────────────────────────────────┘
If you want to rename the directory alone, you can use the -D/--only-dir
flag instead:
f2 -f 'pic' -r 'image' -D
Output:
┌─────────────────────────────┐
| ORIGINAL | RENAMED | STATUS |
| *************************** |
| pics | images | ok |
└─────────────────────────────┘
Ignoring File Extensions
F2 matches the file extension by default, but if this behaviour is not desired, you can use the -e/--ignore-ext
flag.
Without the -e
flag
f2 -f 'jpeg' -r 'jpg'
Output:
┌────────────────────────────────────────────┐
| ORIGINAL | RENAMED | STATUS |
| ****************************************** |
| a-jpeg-file.jpeg | a-jpg-file.jpg | ok |
| file.jpeg | file.jpg | ok |
└────────────────────────────────────────────┘
With the -e
flag
f2 -f 'jpeg' -r 'jpg' -e
Output:
┌─────────────────────────────────────────────┐
| ORIGINAL | RENAMED | STATUS |
| ******************************************* |
| a-jpeg-file.jpeg | a-jpg-file.jpeg | ok |
└─────────────────────────────────────────────┘
Stripping Unwanted Text
You can strip out text by leaving out the -r/--replace
flag. Here's an example that removes -unsplash
from the end of some image files:
f2 -f '-unsplash'
Output:
┌───────────────────────────────────────────────────────────────────────────────────────────────────────┐
| ORIGINAL | RENAMED | STATUS |
| ***************************************************************************************************** |
| nathan-anderson-7TGVEgcTKlY-unsplash.jpg | nathan-anderson-7TGVEgcTKlY.jpg | ok |
| pang-yuhao-WxREM3u9ytk-unsplash.jpg | pang-yuhao-WxREM3u9ytk.jpg | ok |
| rich-hay-PQzlMO1ifPA-unsplash.jpg | rich-hay-PQzlMO1ifPA.jpg | ok |
| samuele-errico-piccarini-t4OxCpKie70-unsplash.jpg | samuele-errico-piccarini-t4OxCpKie70.jpg | ok |
| valentin-salja-VMroCCpP648-unsplash.jpg | valentin-salja-VMroCCpP648.jpg | ok |
| vimal-s-GBg3jyGS-Ug-unsplash.jpg | vimal-s-GBg3jyGS-Ug.jpg | ok |
└───────────────────────────────────────────────────────────────────────────────────────────────────────┘
Renaming with an Index
You can specify an auto incrementing integer in the replacement string using the format below:
%d
: 1,2,3 e.t.c%02d
: 01, 02, 03, e.t.c.%03d
: 001, 002, 003, e.t.c.
...and so on.
f2 -f '.*\.' -r '{%03d}.'
Output:
┌───────────────────────────────────────────────────────────────────────────────────────────────────┐
| ORIGINAL | RENAMED | STATUS |
| ************************************************************************************************* |
| Screenshot 2022-06-18 at 11-31-43 https __vale.dev.png | 001.png | ok |
| Screenshot 2022-06-18 at 11-39-27 Ante.png | 002.png | ok |
| Screenshot 2022-06-18 at 13-49-10 redbean zip listing.png | 003.png | ok |
| Screenshot 2022-06-18 at 13-50-03 redbean zip listing.png | 004.png | ok |
| Screenshot 2022-06-24 at 20-50-50 Should You Get a Ceiling or Standing Fan.png | 005.png | ok |
| Screenshot 2022-07-19 at 08-59-59 Green Africa - Itinerary.png | 006.png | ok |
└───────────────────────────────────────────────────────────────────────────────────────────────────┘
Learn more about indexing here.
Ignoring Cases
F2 is case sensitive by default, but the -i/--ignore-case
flag can be used to make it insensitive to letter cases:
f2 -f 'jpeg' -r 'jpg' -i
┌─────────────────────────────┐
| ORIGINAL | RENAMED | STATUS |
| *************************** |
| a.JPEG | a.jpg | ok |
| b.jpeg | b.jpg | ok |
| c.jPEg | c.jpg | ok |
└─────────────────────────────┘
Using Regex Capture Variables
Regex capture variables are also supported in the replacement string. It can come in handy when you want to base the new filenames on elements in the existing names:
f2 -f '.*-(.*)_(.*)' -r '$1. $2' -e
Output:
┌──────────────────────────────────────────────────────────────────────────────────────────────────────┐
| ORIGINAL | RENAMED | STATUS |
| **************************************************************************************************** |
| The Weeknd_Dawn FM_1-01_Dawn FM.flac | 01. Dawn FM.flac | ok |
| The Weeknd_Dawn FM_1-02_Gasoline.flac | 02. Gasoline.flac | ok |
| The Weeknd_Dawn FM_1-03_How Do I Make You Love Me.flac | 03. How Do I Make You Love Me.flac | ok |
| The Weeknd_Dawn FM_1-04_Take My Breath.flac | 04. Take My Breath.flac | ok |
| The Weeknd_Dawn FM_1-05_Sacrifice.flac | 05. Sacrifice.flac | ok |
| The Weeknd_Dawn FM_1-06_A Tale by Quincy.flac | 06. A Tale by Quincy.flac | ok |
| The Weeknd_Dawn FM_1-07_Out of Time.flac | 07. Out of Time.flac | ok |
| The Weeknd_Dawn FM_1-08_Here We Go… Again.flac | 08. Here We Go… Again.flac | ok |
| The Weeknd_Dawn FM_1-09_Best Friends.flac | 09. Best Friends.flac | ok |
| The Weeknd_Dawn FM_1-10_Is There Someone Else.flac | 10. Is There Someone Else.flac | ok |
| The Weeknd_Dawn FM_1-11_Starry Eyes.flac | 11. Starry Eyes.flac | ok |
| The Weeknd_Dawn FM_1-12_Every Angel Is Terrifying.flac | 12. Every Angel Is Terrifying.flac | ok |
| The Weeknd_Dawn FM_1-13_Don’t Break My Heart.flac | 13. Don’t Break My Heart.flac | ok |
| The Weeknd_Dawn FM_1-14_I Heard You’re Married.flac | 14. I Heard You’re Married.flac | ok |
| The Weeknd_Dawn FM_1-15_Less Than Zero.flac | 15. Less Than Zero.flac | ok |
| The Weeknd_Dawn FM_1-16_Phantom Regret by Jim.flac | 16. Phantom Regret by Jim.flac | ok |
└──────────────────────────────────────────────────────────────────────────────────────────────────────┘
Changing the Directory Structure
If a path separator (/
in all OSes and \
in Windows only) is present in the replacement argument, it will be treated as a path with the last portion being the file or directory name.
Assuming you want to organize some files by categorizing them into subfolders, you only need to add a forward slash in the replacement string such as in the example below:
f2 -f '[^a-zA-Z]*([^(]*) \(([^)]*)\).*\.iso$' -r 'Games/$2/$1{ext}'
Output:
┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
| ORIGINAL | RENAMED | STATUS |
| ***************************************************************************************************************************** |
| 0956 - Call of Duty - Roads to Victory (Germany) (v1.01) [b].iso | Games/Germany/Call of Duty - Roads to Victory.iso | ok |
| 1925 - Gran Turismo (USA) (En,Fr,Es).iso | Games/USA/Gran Turismo.iso | ok |
| 2233 - Metal Gear Solid - Peace Walker (USA) (v1.01).iso | Games/USA/Metal Gear Solid - Peace Walker.iso | ok |
| 3185 - Pro Evolution Soccer 2014 (Europe) (It,El).iso | Games/Europe/Pro Evolution Soccer 2014.iso | ok |
└───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
When executing the operation above, F2 will create the path directories where necessary.
Filtering out Matches
F2 provides the -E/--exclude
flag for the excluding files that would have been matched through the find pattern. This allows you to drill down your search to be specific as possible.
Assuming you want to rename some Webp files, you can do something like this:
f2 -f '.*\.webp' -r '%03d{ext}'
Output:
┌───────────────────────────────────────────────────────────────────┐
| ORIGINAL | RENAMED | STATUS |
| ***************************************************************** |
| 34e7dcd7.webp | 001.webp | ok |
| 3a2107b350fe4173f09a38deebd715bc.webp | 002.webp | ok |
| 7ukau2yqm8y91.webp | 003.webp | ok |
| 7zwffegy91871.webp | 004.webp | ok |
| 9ru90wxqm8y91.webp | 005.webp | ok |
| alan_p.webp | 006.webp | ok |
| bgtqgsxqm8y91.webp | 007.webp | ok |
| dashboard5.webp | 008.webp | ok |
| eiuz4tzc2le71.webp | 009.webp | ok |
| image-2-1.webp | 010.webp | ok |
| qeila4tnvr971.webp | 011.webp | ok |
| sa3a4zxqm8y91.webp | 012.webp | ok |
└───────────────────────────────────────────────────────────────────┘
Let's say you want to exclude files that contain the number 9, you can do something like this:
f2 -f '.*\.webp' -r '%03d{ext}' -E '9'
Output:
┌───────────────────────────────────────────────────────────────────┐
| ORIGINAL | RENAMED | STATUS |
| ***************************************************************** |
| 34e7dcd7.webp | 001.webp | ok |
| alan_p.webp | 002.webp | ok |
| dashboard5.webp | 003.webp | ok |
| eiuz4tzc2le71.webp | 004.webp | ok |
| image-2-1.webp | 005.webp | ok |
| splunk-log-observer-hero-dashboard-plain.webp | 006.webp | ok |
└───────────────────────────────────────────────────────────────────┘
Targeting Specific Files
Another way to narrow down the find and replace operation to specific files is to list the paths to the desired file directly after all the command line options. Assuming the following directory:
sample_flac.flac sample_mp3.mp3 sample_ogg.ogg
Suppose you want to rename sample
to example
but only on the sample_flac.flac
and sample_mp3.mp3
files, you can specify the files that should be matched directly:
f2 -f "sample" -r "example" sample_flac.flac sample_mp3.mp3
Output:
┌───────────────────────────────────────────────┐
| ORIGINAL | RENAMED | STATUS |
| ********************************************* |
| sample_flac.flac | example_flac.flac | ok |
| sample_mp3.mp3 | example_mp3.mp3 | ok |
└───────────────────────────────────────────────┘
Notice that the sample_ogg.ogg
file isn't included even though it matches the find pattern. When you specify a set of files as above, only those files will be searched for matches even if other files would ordinarily be matched.
Chaining Renaming Operations
With F2, you can chain as many renaming operations as you want in a single command. This makes it easy to selectively replace different aspects of file names. The first combination selects the pool of files that will be worked on, while subsequent ones act on the results of the previous one. If this concept sounds confusing, this example below should make it clearer:
f2 -f '[^a-zA-Z]*([^(]*) \\(([^)]*)\\).*\\.iso$' -r 'Games/$2/$1{ext}' -f ' - ([^.]*)' -r ' ({<$1>.up})'
┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
| ORIGINAL | RENAMED | STATUS |
| ***************************************************************************************************************************** |
| 0956 - Call of Duty - Roads to Victory (Germany) (v1.01) [b].iso | Games/Germany/Call of Duty (ROADS TO VICTORY).iso | ok |
| 1925 - Gran Turismo (USA) (En,Fr,Es).iso | Games/USA/Gran Turismo.iso | ok |
| 2233 - Metal Gear Solid - Peace Walker (USA) (v1.01).iso | Games/USA/Metal Gear Solid (PEACE WALKER).iso | ok |
| 3185 - Pro Evolution Soccer 2014 (Europe) (It,El).iso | Games/Europe/Pro Evolution Soccer 2014.iso | ok |
└───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
Notice how the -f
and -r
flags can be used multiple times in a single renaming operation. The first combination (-f '[^a-zA-Z]*([^(]*) \\(([^)]*)\\).*\\.iso$' -r 'Games/$2/$1{ext}'
) yields the following intermediate result:
Games/Germany/Call of Duty - Roads to Victory.iso
Games/USA/Gran Turismo.iso
Games/USA/Metal Gear Solid - Peace Walker.iso
Games/Europe/Pro Evolution Soccer 2014.iso
Afterward, the next combination targets the characters after hypen, uppercases them and places them in parenthesis in the new name thus yielding the final result.
Integration with Other Programs
You can combine F2 with other tools using pipes to pass file arguments. Here's an example that finds files modified before the last 30 days and renames them:
find -type f -mtime +30 | f2 -r '{mtime.YYYY}-{mtime.MM}-{mtime.DD}_{f}{ext}'
Output:
┌─────────────────────────────────────────────────────────────────────────────────────────────────┐
| ORIGINAL | RENAMED | STATUS |
| *********************************************************************************************** |
| upload-files-go.md | 2022-10-23_upload-files-go.md | ok |
| windows-terminal.md | 2022-10-23_windows-terminal.md | ok |
└─────────────────────────────────────────────────────────────────────────────────────────────────┘