diff --git a/.gitignore b/.gitignore index 339dca1..f6c5276 100755 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,5 @@ t.* binaries brename_* *.brename_detail.txt + +example/ diff --git a/README.md b/README.md index 0918c4b..055114a 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# brename -- a practical cross-platform command-line tool for safely batch renaming files/directories via regular expression +# brename: batch renaming safely [![Built with GoLang](https://img.shields.io/badge/powered_by-go-6362c2.svg?style=flat)](https://golang.org) [![Go Report Card](https://goreportcard.com/badge/github.com/shenwei356/brename)](https://goreportcard.com/report/github.com/shenwei356/brename) @@ -8,6 +8,8 @@ `brename` is a cross-platform command-line tool for safely batch renaming files/directories via regular expression. + + ## Table of Contents @@ -30,23 +32,37 @@ Some operations are allowed on Linux, while they could be dangerous on Windows. [For example](https://github.com/shenwei356/brename/issues/28), renaming `test.tar.gz` to `test.tar` will overwrite `TEST.tar`. `brename` (v2.13.0 and later versions) can handle these cases appropriately (`-w` and `-W`). -- **Safe**. By ***checking potential conflicts and errors***. -- **Supporting Undo** the LAST successful operation. -- **Overwrite can be detected and users can choose whether overwrite or leave it**. -- **File filtering**. Supporting including and excluding files via regular expression. - No need to run commands like `find ./ -name "*.html" -exec CMD`. -- **Renaming submatch with corresponding value via key-value file**. -- **Renaming via ascending integer**. -- **Automatically making directoy**: `a-b-c.txt` -> `a/b/c.txt` -- **Recursively renaming both files and directories**. -- **Supporting dry run**. -- **Colorful output**. Screenshots: - - Linux - ![linux](screenshot/linux.png) - - Windows +- **Safe**. ***It helps you check potential conflicts and errors before it's too late***. + + + + Some common conflict and errors that might happen with commands like `mv` or `rename`. + + - `New path existed`: **Existed files might be overwritten, causing data loss**. + - `Overwriting newly renamed path`. **Existed files might be overwritten, causing data loss.** + This case is hard to check by eyes. + - `Missing target`: New file is empty, that's not allowed. + - `New path ending with a space`: Not allowed in Windows. It's legal in Linux, but might cause unexpected errors. + - `New path ending with a period`: Not allowed in Windows. + +- **Supporting dry run**. A good habbit. + + + +- **Supporting Undo** the LAST successful operation, like a time machine. + + + +- **Overwrite can be detected and users can choose whether overwrite or leave it** (`-o/--overwrite-mode`). +- **File filtering**. + - Supporting including (`-f/--include-filters`) and excluding (`-F/--exclude-filters`) files via regular expression. + - No need to run commands like `find ./ -name "*.html" -exec CMD`. +- **Renaming submatch with corresponding value via key-value file** (`-r "{kv}" -k kv.tsv`). +- **Renaming via ascending integer** (`-r "{nr}"`). +- **Automatically making directoy**: e.g., renaming `a-b-c.txt` to `a/b/c.txt`. +- **Recursively renaming both files and directories** (`-R/--recursive`, `-D/--including-dir`, `--only-dir`). - ![windows](screenshot/windows.png) ## Installation @@ -57,20 +73,20 @@ #### Method 1: Download binaries -[brename v2.13.0](https://github.com/shenwei356/brename/releases/tag/v2.13.0) -[![Github Releases (by Release)](https://img.shields.io/github/downloads/shenwei356/brename/v2.13.0/total.svg)](https://github.com/shenwei356/brename/releases/tag/v2.13.0) +[brename v2.14.0](https://github.com/shenwei356/brename/releases/tag/v2.14.0) +[![Github Releases (by Release)](https://img.shields.io/github/downloads/shenwei356/brename/v2.14.0/total.svg)](https://github.com/shenwei356/brename/releases/tag/v2.14.0) ***Tip: run `brename -V` to check update !!!*** OS |Arch |File, 中国镜像 |Download Count :------|:---------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -Linux |32-bit |[brename_linux_386.tar.gz](https://github.com/shenwei356/brename/releases/download/v2.13.0/brename_linux_386.tar.gz),
[中国镜像](http://app.shenwei.me/data/brename/brename_linux_386.tar.gz) |[![Github Releases (by Asset)](https://img.shields.io/github/downloads/shenwei356/brename/latest/brename_linux_386.tar.gz.svg?maxAge=3600)](https://github.com/shenwei356/brename/releases/download/v2.13.0/brename_linux_386.tar.gz) -Linux |**64-bit**|[**brename_linux_amd64.tar.gz**](https://github.com/shenwei356/brename/releases/download/v2.13.0/brename_linux_amd64.tar.gz),
[中国镜像](http://app.shenwei.me/data/brename/brename_linux_amd64.tar.gz) |[![Github Releases (by Asset)](https://img.shields.io/github/downloads/shenwei356/brename/latest/brename_linux_amd64.tar.gz.svg?maxAge=3600)](https://github.com/shenwei356/brename/releases/download/v2.13.0/brename_linux_amd64.tar.gz) -Linux |arm64 |[**brename_linux_arm64.tar.gz**](https://github.com/shenwei356/brename/releases/download/v2.13.0/brename_linux_arm64.tar.gz),
[中国镜像](http://app.shenwei.me/data/brename/brename_linux_arm64.tar.gz) |[![Github Releases (by Asset)](https://img.shields.io/github/downloads/shenwei356/brename/latest/brename_linux_arm64.tar.gz.svg?maxAge=3600)](https://github.com/shenwei356/brename/releases/download/v2.13.0/brename_linux_arm64.tar.gz) -OS X |**64-bit**|[**brename_darwin_amd64.tar.gz**](https://github.com/shenwei356/brename/releases/download/v2.13.0/brename_darwin_amd64.tar.gz),
[中国镜像](http://app.shenwei.me/data/brename/brename_darwin_amd64.tar.gz) |[![Github Releases (by Asset)](https://img.shields.io/github/downloads/shenwei356/brename/latest/brename_darwin_amd64.tar.gz.svg?maxAge=3600)](https://github.com/shenwei356/brename/releases/download/v2.13.0/brename_darwin_amd64.tar.gz) -OS X |arm64 |[**brename_darwin_arm64.tar.gz**](https://github.com/shenwei356/brename/releases/download/v2.13.0/brename_darwin_arm64.tar.gz),
[中国镜像](http://app.shenwei.me/data/brename/brename_darwin_arm64.tar.gz) |[![Github Releases (by Asset)](https://img.shields.io/github/downloads/shenwei356/brename/latest/brename_darwin_arm64.tar.gz.svg?maxAge=3600)](https://github.com/shenwei356/brename/releases/download/v2.13.0/brename_darwin_arm64.tar.gz) -Windows|32-bit |[brename_windows_386.exe.tar.gz](https://github.com/shenwei356/brename/releases/download/v2.13.0/brename_windows_386.exe.tar.gz),
[中国镜像](http://app.shenwei.me/data/brename/brename_windows_386.exe.tar.gz) |[![Github Releases (by Asset)](https://img.shields.io/github/downloads/shenwei356/brename/latest/brename_windows_386.exe.tar.gz.svg?maxAge=3600)](https://github.com/shenwei356/brename/releases/download/v2.13.0/brename_windows_386.exe.tar.gz) -Windows|**64-bit**|[**brename_windows_amd64.exe.tar.gz**](https://github.com/shenwei356/brename/releases/download/v2.13.0/brename_windows_amd64.exe.tar.gz),
[中国镜像](http://app.shenwei.me/data/brename/brename_windows_amd64.exe.tar.gz)|[![Github Releases (by Asset)](https://img.shields.io/github/downloads/shenwei356/brename/latest/brename_windows_amd64.exe.tar.gz.svg?maxAge=3600)](https://github.com/shenwei356/brename/releases/download/v2.13.0/brename_windows_amd64.exe.tar.gz) +Linux |32-bit |[brename_linux_386.tar.gz](https://github.com/shenwei356/brename/releases/download/v2.14.0/brename_linux_386.tar.gz),
[中国镜像](http://app.shenwei.me/data/brename/brename_linux_386.tar.gz) |[![Github Releases (by Asset)](https://img.shields.io/github/downloads/shenwei356/brename/latest/brename_linux_386.tar.gz.svg?maxAge=3600)](https://github.com/shenwei356/brename/releases/download/v2.14.0/brename_linux_386.tar.gz) +Linux |**64-bit**|[**brename_linux_amd64.tar.gz**](https://github.com/shenwei356/brename/releases/download/v2.14.0/brename_linux_amd64.tar.gz),
[中国镜像](http://app.shenwei.me/data/brename/brename_linux_amd64.tar.gz) |[![Github Releases (by Asset)](https://img.shields.io/github/downloads/shenwei356/brename/latest/brename_linux_amd64.tar.gz.svg?maxAge=3600)](https://github.com/shenwei356/brename/releases/download/v2.14.0/brename_linux_amd64.tar.gz) +Linux |arm64 |[**brename_linux_arm64.tar.gz**](https://github.com/shenwei356/brename/releases/download/v2.14.0/brename_linux_arm64.tar.gz),
[中国镜像](http://app.shenwei.me/data/brename/brename_linux_arm64.tar.gz) |[![Github Releases (by Asset)](https://img.shields.io/github/downloads/shenwei356/brename/latest/brename_linux_arm64.tar.gz.svg?maxAge=3600)](https://github.com/shenwei356/brename/releases/download/v2.14.0/brename_linux_arm64.tar.gz) +OS X |**64-bit**|[**brename_darwin_amd64.tar.gz**](https://github.com/shenwei356/brename/releases/download/v2.14.0/brename_darwin_amd64.tar.gz),
[中国镜像](http://app.shenwei.me/data/brename/brename_darwin_amd64.tar.gz) |[![Github Releases (by Asset)](https://img.shields.io/github/downloads/shenwei356/brename/latest/brename_darwin_amd64.tar.gz.svg?maxAge=3600)](https://github.com/shenwei356/brename/releases/download/v2.14.0/brename_darwin_amd64.tar.gz) +OS X |arm64 |[**brename_darwin_arm64.tar.gz**](https://github.com/shenwei356/brename/releases/download/v2.14.0/brename_darwin_arm64.tar.gz),
[中国镜像](http://app.shenwei.me/data/brename/brename_darwin_arm64.tar.gz) |[![Github Releases (by Asset)](https://img.shields.io/github/downloads/shenwei356/brename/latest/brename_darwin_arm64.tar.gz.svg?maxAge=3600)](https://github.com/shenwei356/brename/releases/download/v2.14.0/brename_darwin_arm64.tar.gz) +Windows|32-bit |[brename_windows_386.exe.tar.gz](https://github.com/shenwei356/brename/releases/download/v2.14.0/brename_windows_386.exe.tar.gz),
[中国镜像](http://app.shenwei.me/data/brename/brename_windows_386.exe.tar.gz) |[![Github Releases (by Asset)](https://img.shields.io/github/downloads/shenwei356/brename/latest/brename_windows_386.exe.tar.gz.svg?maxAge=3600)](https://github.com/shenwei356/brename/releases/download/v2.14.0/brename_windows_386.exe.tar.gz) +Windows|**64-bit**|[**brename_windows_amd64.exe.tar.gz**](https://github.com/shenwei356/brename/releases/download/v2.14.0/brename_windows_amd64.exe.tar.gz),
[中国镜像](http://app.shenwei.me/data/brename/brename_windows_amd64.exe.tar.gz)|[![Github Releases (by Asset)](https://img.shields.io/github/downloads/shenwei356/brename/latest/brename_windows_amd64.exe.tar.gz.svg?maxAge=3600)](https://github.com/shenwei356/brename/releases/download/v2.14.0/brename_windows_amd64.exe.tar.gz) Just [download](https://github.com/shenwei356/brename/releases) compressed @@ -128,7 +144,7 @@ And then: ``` -brename -- a practical cross-platform command-line tool for safely batch renaming files/directories via regular expression +brename: a practical cross-platform command-line tool for safely batch renaming files/directories via regular expression Version: 2.14.0 @@ -141,15 +157,15 @@ Warnings: -w/--case-insensitive-path to correctly check file overwrites. 2. The flag -w/--case-insensitive-path is switched on by default on Windows, please use -W/--case-sensitive-path to disable it if the file system is indeed case-sensitive. - 3. New paths ending with a period of space, being error-prone, are not allowed. + 3. New paths ending with periods of spaces, being error-prone, are not allowed. Three path filters: 1. -S/--skip-filters black list default value: ^\. (skipping paths starting with ".") 2. -F/--exclude-filters black list no default value 3. -f/--include-filters white list default value: . (anything) - - Notes: + + Notes: 1. Paths starting with "." are ignored by default, disable this with -S "". 2. These options support multiple values, e.g., -f ".html" -f ".htm". But ATTENTION: each comma in filters is treated as a separator of multiple filters. @@ -166,7 +182,7 @@ Special replacement symbols: n can be specified by flag -I/--key-capt-idx (default: 1) Usage: - brename [flags] + brename [flags] Examples: 1. dry run and showing potential dangerous operations (-d) @@ -241,7 +257,7 @@ Flags: -o, --overwrite-mode int overwrite mode (0 for reporting error, 1 for overwrite, 2 for not renaming) (default 0) -p, --pattern string search pattern (regular expression) - -q, --quiet be quiet, do not show information and warning + -q, --quiet be quiet, do not show any information and warning -R, --recursive rename recursively -r, --replacement string replacement. capture variables supported. e.g. $1 represents the first submatch. ATTENTION: for *nix OS, use SINGLE quote NOT double @@ -254,8 +270,8 @@ Flags: patterns containing comma, e.g., -p '"A{2,}"' (default [^\.]) -n, --start-num int starting number when using {nr} in replacement (default 1) -u, --undo undo the LAST successful operation - -v, --verbose int verbose level (0 for all, 1 for warning and error, 2 for only error) - (default 0) + -v, --verbose int verbose level (0 for all, 1 for warning, error and renamed files, 2 + for only error and renamed files) (default 2) -V, --version print version information and check for update ``` @@ -283,30 +299,25 @@ Take a directory for example (run `generate-example-folder.sh` to generate) A dry run is firstly performed for safety checking (`-d/--dry-run`). $ brename -p "\.jpeg" -r ".jpg" -R -d - [INFO] main options: - [INFO] ignore case: false - [INFO] search pattern: \.jpeg - [INFO] include filters: . - [INFO] search paths: ./ - [INFO] - [INFO] checking: [ ok ] 'a.jpeg' -> 'a.jpg' - [INFO] checking: [ ok ] 'b.jpeg' -> 'b.jpg' - [INFO] 2 path(s) to be renamed + Searching for paths to rename... + + [OK] example/a.jpeg -> example/a.jpg + [OK] example/b.jpeg -> example/b.jpg + + 2 path(s) to be renamed $ brename -p "\.jpeg" -r ".jpg" -R - [INFO] main options: - [INFO] ignore case: false - [INFO] search pattern: \.jpeg - [INFO] include filters: . - [INFO] search paths: ./ - [INFO] - [INFO] checking: [ ok ] 'a.jpeg' -> 'a.jpg' - [INFO] checking: [ ok ] 'b.jpeg' -> 'b.jpg' - [INFO] 2 path(s) to be renamed - [INFO] renamed: 'a.jpeg' -> 'a.jpg' - [INFO] renamed: 'b.jpeg' -> 'b.jpg' - [INFO] 2 path(s) renamed + Searching for paths to rename... + + Done searching. + + Renaming paths... + + [DONE] example/a.jpeg -> example/a.jpg + [DONE] example/b.jpeg -> example/b.jpg + + 2 path(s) renamed in 0.001 seconds $ tree . @@ -322,11 +333,14 @@ Take a directory for example (run `generate-example-folder.sh` to generate) 1. **Undo** the LAST successful operation, yes it's COOL! (`-u/--undo`, `-U/--force-undo`) $ brename -u - [INFO] rename back: 'b.jpg' -> 'b.jpeg' - [INFO] rename back: 'a.jpg' -> 'a.jpeg' - [INFO] 2 path(s) renamed + Renaming paths back... + + [DONE] example/b.jpg -> example/b.jpeg + [DONE] example/a.jpg -> example/a.jpeg + + 2 path(s) renamed back in 0.000 seconds - Disable undo if you do not want to create .brename_detail.txt (`-x`) + Disable undo if you do not want to create `.brename_detail.txt` (`-x`) $ brename -p xxx -r yyy -x @@ -334,28 +348,40 @@ Take a directory for example (run `generate-example-folder.sh` to generate) $ brename --clear -R -1. Dry run and only showing operations that will cause error (`-v/--verbose`) +1. Dry run, only showing operations that will cause error (just remove `-d`). # default value of -v is 0 $ brename -p a -r b -R -D -d - [INFO] checking: [ ok ] 'a.html' -> 'b.html' - [ERRO] checking: [ new path existed ] 'a.jpg' -> 'b.jpg' - [INFO] checking: [ ok ] 'abc' -> 'bbc' - [ERRO] 1 potential error(s) detected, please check + Searching for paths to rename... + + [OK] a.html -> b.html + [new path existed] a.jpeg -> b.jpeg + [OK] abc -> bbc - $ brename -p a -r b -R -D -d -v 2 - [ERRO] checking: [ new path existed ] 'a.jpg' -> 'b.jpg' - [ERRO] 1 potential error(s) detected, please check + 1 potential error(s) detected, please check + + $ brename -p a -r b -R -D + Searching for paths to rename... + + Done searching. + [new path existed] example/a.jpeg -> example/b.jpeg + + 1 potential error(s) detected, please check 1. Ignoring cases (`-i/--ignore-case`) $ brename -p "\.jpeg" -r ".jpg" -R -i - [INFO] checking: [ ok ] 'abc/A.JPEG' -> 'abc/A.jpg' - [INFO] checking: [ ok ] 'abc/B.JPEG' -> 'abc/B.jpg' - [INFO] 2 path(s) to be renamed - [INFO] renamed: 'abc/A.JPEG' -> 'abc/A.jpg' - [INFO] renamed: 'abc/B.JPEG' -> 'abc/B.jpg' - [INFO] 2 path(s) renamed + Searching for paths to rename... + + Done searching. + + Renaming paths... + + [DONE] abc/A.JPEG -> abc/A.jpg + [DONE] abc/B.JPEG -> abc/B.jpg + + 2 path(s) renamed in 0.000 seconds + $ tree . @@ -371,12 +397,16 @@ Take a directory for example (run `generate-example-folder.sh` to generate) # or brename -p "(a)" -r '$1$1' in Linux/Mac OS X $ brename -p "(a)" -r "\$1\$1" -i - [INFO] checking: [ ok ] 'a.html' -> 'aa.html' - [INFO] checking: [ ok ] 'a.jpg' -> 'aa.jpg' - [INFO] 2 path(s) to be renamed - [INFO] renamed: 'a.html' -> 'aa.html' - [INFO] renamed: 'a.jpg' -> 'aa.jpg' - [INFO] 2 path(s) renamed + Searching for paths to rename... + + Done searching. + + Renaming paths... + + [DONE] a.html -> aa.html + [DONE] a.jpg -> aa.jpg + + 2 path(s) renamed in 0.000 seconds $ tree . @@ -391,14 +421,17 @@ Take a directory for example (run `generate-example-folder.sh` to generate) 1. Renaming directory too (`-D/--including-dir`), even renaming directory only (`-D --only-dir`) $ brename -p "a" -r "A" -R -D - [INFO] checking: [ ok ] 'aa.html' -> 'AA.html' - [INFO] checking: [ ok ] 'aa.jpg' -> 'AA.jpg' - [INFO] checking: [ ok ] 'abc' -> 'Abc' - [INFO] 3 path(s) to be renamed - [INFO] renamed: 'aa.html' -> 'AA.html' - [INFO] renamed: 'aa.jpg' -> 'AA.jpg' - [INFO] renamed: 'abc' -> 'Abc' - [INFO] 3 path(s) renamed + Searching for paths to rename... + + Done searching. + + Renaming paths... + + [DONE] aa.html -> AA.html + [DONE] aa.jpg -> AA.jpg + [DONE] abc -> Abc + + 3 path(s) renamed in 0.001 seconds $ tree . @@ -413,70 +446,65 @@ Take a directory for example (run `generate-example-folder.sh` to generate) 1. **Only renaming specific files via include filters (regular expression) (`-f/--include-filters`)** - $ brename -p '(.)' -r '$1 ' -d - [INFO] main options: - [INFO] ignore case: false - [INFO] search pattern: (.) - [INFO] include filters: . - [INFO] search paths: ./ - [INFO] - [INFO] checking: [ ok ] 'AA.html' -> 'A A . h t m l ' - [INFO] checking: [ ok ] 'AA.jpg' -> 'A A . j p g ' - [INFO] checking: [ ok ] 'b.jpg' -> 'b . j p g ' - [INFO] 3 path(s) to be renamed + $ brename -p '(.)' -r ' $1' -d + Searching for paths to rename... + + [OK] AA.html -> A A . h t m l + [OK] AA.jpg -> A A . j p g + [OK] b.jpg -> b . j p g + + 3 path(s) to be renamed + - $ brename -p '(.)' -r '$1 ' -d -f '\.jpg$' - [INFO] main options: - [INFO] ignore case: false - [INFO] search pattern: (.) - [INFO] include filters: \.jpg$ - [INFO] search paths: ./ - [INFO] - [INFO] checking: [ ok ] 'AA.jpg' -> 'A A . j p g ' - [INFO] checking: [ ok ] 'b.jpg' -> 'b . j p g ' - [INFO] 2 path(s) to be renamed + $ brename -p '(.)' -r ' $1' -d -f '\.jpg$' + Searching for paths to rename... + + [OK] AA.jpg -> A A . j p g + [OK] b.jpg -> b . j p g + + 2 path(s) to be renamed ***Attention: value of `-f/--include-filters` and `-F/--exclude-filters` should be regular expression, NOT wildcard!*** $ brename -p '(.)' -r '$1 ' -d -f *.jpg - [WARN] Seems you are using wildcard for -f/--include-filters? Make sure using regular expression: AA.jpg - [INFO] main options: - [INFO] ignore case: false - [INFO] search pattern: (.) - [INFO] include filters: AA.jpg - [INFO] search paths: b.jpg - [INFO] - [INFO] 0 path(s) to be renamed + Seems you are using wildcard for -f/--include-filters? Make sure using regular expression: AA.jpg + Searching for paths to rename... + + + 0 path(s) to be renamed $ brename -p '(.)' -r '$1 ' -d -f '*.jpg' - [WARN] Are you using wildcard for -f/--include-filters? It should be regular expression: *.jpg - [ERRO] illegal regular expression for include filter: *.jpg + Are you using wildcard for -f/--include-filters? It should be regular expression: *.jpg + illegal regular expression for include filter: *.jpg $ brename -p '(.)' -r '$1 ' -d -f A* - [WARN] Seems you are using wildcard for -f/--include-filters? Make sure using regular expression: AA.html - [INFO] main options: - [INFO] ignore case: false - [INFO] search pattern: (.) - [INFO] include filters: AA.html - [INFO] search paths: AA.jpg, Abc - [INFO] - [INFO] 0 path(s) to be renamed + Seems you are using wildcard for -f/--include-filters? Make sure using regular expression: AA.html + Searching for paths to rename... + + + 0 path(s) to be renamed 1. Excluding files via exclude filters (regular expression) (`-F/--exclude-filters`) - $ brename -p '(.)' -r '$1 ' -d - [INFO] checking: [ ok ] 'AA.jpg' -> 'A A . j p g ' - [INFO] checking: [ ok ] 'b.jpg' -> 'b . j p g ' - [INFO] checking: [ ok ] 'hello AA.html' -> 'h e l l o A A . h t m l ' - [INFO] 3 path(s) to be renamed + $ brename -p '(.)' -r ' $1' -d + Searching for paths to rename... + [OK] AA.html -> A A . h t m l + [OK] AA.jpg -> A A . j p g + [OK] b.jpg -> b . j p g - $ brename -p '(.)' -r '$1 ' -d -F '\.html$' - [INFO] checking: [ ok ] 'AA.jpg' -> 'A A . j p g ' - [INFO] checking: [ ok ] 'b.jpg' -> 'b . j p g ' - [INFO] 2 path(s) to be renamed + 3 path(s) to be renamed + + + $ brename -p '(.)' -r ' $1' -d -F '\.html$' + Searching for paths to rename... + + [OK] AA.jpg -> A A . j p g + [OK] b.jpg -> b . j p g + + 2 path(s) to be renamed 1. Skipping files via skip filter (regular expression) (`-S/--skip-filters`). This filter step is performed before the exclude filters. The default value `^\.` is for skipping files starting with dot, which are hidden configuration files in Linux. @@ -487,29 +515,43 @@ Take a directory for example (run `generate-example-folder.sh` to generate) 1. Do not touch file extension (`-e/--ignore-ext`) - $ brename -p '(.)' -r '$1 ' -d - [INFO] checking: [ ok ] 'AA.jpg' -> 'A A . j p g ' - [INFO] checking: [ ok ] 'b.jpg' -> 'b . j p g ' - [INFO] checking: [ ok ] 'hello AA.html' -> 'h e l l o A A . h t m l ' - [INFO] 3 path(s) to be renamed + $ brename -p '(.)' -r ' $1' -d + Searching for paths to rename... + + [OK] AA.html -> A A . h t m l + [OK] AA.jpg -> A A . j p g + [OK] b.jpg -> b . j p g - $ brename -p '(.)' -r '$1 ' -d -e - [INFO] checking: [ ok ] 'AA.jpg' -> 'A A .jpg' - [INFO] checking: [ ok ] 'b.jpg' -> 'b .jpg' - [INFO] checking: [ ok ] 'hello AA.html' -> 'h e l l o A A .html' - [INFO] 3 path(s) to be renamed + 3 path(s) to be renamed + + $ brename -p '(.)' -r ' $1' -d -e + Searching for paths to rename... + + [OK] AA.html -> A A.html + [OK] AA.jpg -> A A.jpg + [OK] b.jpg -> b.jpg + + 3 path(s) to be renamed 1. Renaming with number (-r `{nr}`) $ brename -d -p '(.+)\.' -r 'pic-{nr}.' -f .jpg -d - [INFO] checking: [ ok ] 'AA.jpg' -> 'pic-1.jpg' - [INFO] checking: [ ok ] 'b.jpg' -> 'pic-2.jpg' - [INFO] 2 path(s) to be renamed + Searching for paths to rename... + + [OK] AA.jpg -> pic-1.jpg + [OK] b.jpg -> pic-2.jpg + + 2 path(s) to be renamed + $ brename -d -p '(.+)\.' -r 'pic-{nr}.' -f .jpg -d --nr-width 3 --start-num 11 - [INFO] checking: [ ok ] 'AA.jpg' -> 'pic-011.jpg' - [INFO] checking: [ ok ] 'b.jpg' -> 'pic-012.jpg' - [INFO] 2 path(s) to be renamed + Searching for paths to rename... + + [OK] AA.jpg -> pic-011.jpg + [OK] b.jpg -> pic-012.jpg + + 2 path(s) to be renamed + 1. Replace submatch with corresponding value via tab delimited key-value file (`-k/--kv-file`) @@ -519,20 +561,31 @@ Take a directory for example (run `generate-example-folder.sh` to generate) c 三 $ brename -p '^(\w)' -r '{kv}' -k kv.tsv -K -i -d - [INFO] read key-value file: kv.tsv - [INFO] 3 pairs of key-value loaded - [INFO] checking: [ ok ] 'AA.jpg' -> '一A.jpg' - [INFO] checking: [ ok ] 'b.jpg' -> '二.jpg' - [WARN] checking: [ unchanged ] 'hello b.html' -> 'hello b.html' - [WARN] checking: [ unchanged ] 'kv.tsv' -> 'kv.tsv' + read key-value file: kv.tsv + 3 pairs of key-value loaded + Searching for paths to rename... + + [OK] AA.html -> 一A.html + [OK] AA.jpg -> 一A.jpg + [OK] b.jpg -> 二.jpg + [unchanged] kv.tsv -> kv.tsv + + 3 path(s) to be renamed 1. Auto mkdir + $ touch a-b-c.txt + $ brename -f .txt -p '-' -r '/' - [INFO] checking: [ ok ] 'a-b-c.txt' -> 'a/b/c.txt' - [INFO] 1 path(s) to be renamed - [INFO] renamed: 'a-b-c.txt' -> 'a/b/c.txt' - [INFO] 1 path(s) renamed + Searching for paths to rename... + + Done searching. + + Renaming paths... + + [DONE] a-b-c.txt -> a/b/c.txt + + 1 path(s) renamed in 0.000 seconds $ tree a a @@ -566,43 +619,33 @@ Take a directory for example (run `generate-example-folder.sh` to generate) 1. default mode: reporting error $ brename -p 386 -r amd64 -d - [ERRO] checking: [ new path existed ] 'brename_darwin_386.tar.gz' -> 'brename_darwin_amd64.tar.gz' - [ERRO] checking: [ new path existed ] 'brename_linux_386.tar.gz' -> 'brename_linux_amd64.tar.gz' - [ERRO] checking: [ new path existed ] 'brename_windows_386.exe.tar.gz' -> 'brename_windows_amd64.exe.tar.gz' - [ERRO] 3 potential error(s) detected, please check + Searching for paths to rename... + + [new path existed] brename_linux_386.tar.gz -> brename_linux_amd64.tar.gz + [new path existed] brename_windows_386.exe.tar.gz -> brename_windows_amd64.exe.tar.gz + + 2 potential error(s) detected, please check 1. allowing overwrite $ brename -p 386 -r amd64 -d -o 1 - [WARN] checking: [ new path existed ] 'brename_darwin_386.tar.gz' -> 'brename_darwin_amd64.tar.gz' (will be overwrited) - [WARN] checking: [ new path existed ] 'brename_linux_386.tar.gz' -> 'brename_linux_amd64.tar.gz' (will be overwrited) - [WARN] checking: [ new path existed ] 'brename_windows_386.exe.tar.gz' -> 'brename_windows_amd64.exe.tar.gz' (will be overwrited) - [INFO] 3 path(s) to be renamed + Searching for paths to rename... + + [new path existed] brename_linux_386.tar.gz -> brename_linux_amd64.tar.gz (will be overwrited) + [new path existed] brename_windows_386.exe.tar.gz -> brename_windows_amd64.exe.tar.gz (will be overwrited) + + 2 path(s) to be renamed 1. leave it $ brename -p 386 -r amd64 -d -o 2 - [WARN] checking: [ new path existed ] 'brename_darwin_386.tar.gz' -> 'brename_darwin_amd64.tar.gz' (will NOT be overwrited) - [WARN] checking: [ new path existed ] 'brename_linux_386.tar.gz' -> 'brename_linux_amd64.tar.gz' (will NOT be overwrited) - [WARN] checking: [ new path existed ] 'brename_windows_386.exe.tar.gz' -> 'brename_windows_amd64.exe.tar.gz' (will NOT be overwrited) - [INFO] 0 path(s) to be renamed + Searching for paths to rename... - 1. this flag also works for another case, where two or more files are renamed to same new path + [new path existed] brename_linux_386.tar.gz -> brename_linux_amd64.tar.gz (will NOT be overwrited) + [new path existed] brename_windows_386.exe.tar.gz -> brename_windows_amd64.exe.tar.gz (will NOT be overwrited) - $ brename -f 386 -p 'darwin|linux' -r unix-like -d - [INFO] checking: [ ok ] 'brename_darwin_386.tar.gz' -> 'brename_unix-like_386.tar.gz' - [ERRO] checking: [ overwriting newly renamed path ] 'brename_linux_386.tar.gz' -> 'brename_unix-like_386.tar.gz' - [ERRO] 1 potential error(s) detected, please check + 0 path(s) to be renamed - $ brename -f 386 -p 'darwin|linux' -r unix-like -d -o 1 - [INFO] checking: [ ok ] 'brename_darwin_386.tar.gz' -> 'brename_unix-like_386.tar.gz' - [WARN] checking: [ overwriting newly renamed path ] 'brename_linux_386.tar.gz' -> 'brename_unix-like_386.tar.gz' (will be overwrited) - [INFO] 2 path(s) to be renamed - - $ brename -f 386 -p 'darwin|linux' -r unix-like -d -o 2 - [INFO] checking: [ ok ] 'brename_darwin_386.tar.gz' -> 'brename_unix-like_386.tar.gz' - [WARN] checking: [ overwriting newly renamed path ] 'brename_linux_386.tar.gz' -> 'brename_unix-like_386.tar.gz' (will NOT be overwrited) - [INFO] 1 path(s) to be renamed ## Real-world examples @@ -611,21 +654,27 @@ Take a directory for example (run `generate-example-folder.sh` to generate) $ ls GCF_029211165.1_ASM2921116v1_genomic.fa + # ------------------------------------------------------------------------ # only keeping accession + + Searching for paths to rename... + + [OK] GCF_029211165.1_ASM2921116v1_genomic.fa -> GCF_029211165.fa + + 1 path(s) to be renamed + + # ------------------------------------------------------------------------ + # keeping accession.version $ brename -R -p '^(\w{3}_\d{9}\.\d+).+' -r '$1.fa' -d - [INFO] search paths: ./ - [INFO] - [INFO] checking: [ ok ] 'GCF_029211165.1_ASM2921116v1_genomic.fa' -> 'GCF_029211165.1.fa' - [INFO] 1 path(s) to be renamed + Searching for paths to rename... + + [OK] GCF_029211165.1_ASM2921116v1_genomic.fa -> GCF_029211165.1.fa + + 1 path(s) to be renamed - # keeping accession.version - $ brename -R -e -p '\..+' -d - [INFO] search paths: ./ - [INFO] - [INFO] checking: [ ok ] 'GCF_029211165.1_ASM2921116v1_genomic.fa' -> 'GCF_029211165.fa' - [INFO] 1 path(s) to be renamed + 1. Replace matches with corresponding pairing values diff --git a/brename.go b/brename.go index 056d2c6..d1c847f 100644 --- a/brename.go +++ b/brename.go @@ -1,4 +1,4 @@ -// Copyright © 2013-2022 Wei Shen +// Copyright © 2013-2024 Wei Shen // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -176,7 +176,7 @@ func getOptions(cmd *cobra.Command) *Options { log.Warningf("something wrong when trying to check whether %s is a existed file", infilter) } if existed { - log.Warningf("Seems you are using wildcard for -f/--include-filters? Make sure using regular expression: %s", infilter) + log.Warning("Seems you are using wildcard for -f/--include-filters? Make sure using regular expression: %s", infilter) } } @@ -461,7 +461,7 @@ func init() { log = logging.MustGetLogger(app) RootCmd.Flags().BoolP("quiet", "q", false, "be quiet, do not show any information and warning") - RootCmd.Flags().IntP("verbose", "v", 2, "verbose level (0 for all, 1 for warning, error and renamed files, 2 for only error and renamed files) (default 2)") + RootCmd.Flags().IntP("verbose", "v", 2, "verbose level (0 for all, 1 for warning, error and renamed files, 2 for only error and renamed files)") RootCmd.Flags().BoolP("version", "V", false, "print version information and check for update") RootCmd.Flags().BoolP("dry-run", "d", false, "print rename operations but do not run") @@ -659,7 +659,7 @@ var RootCmd = &cobra.Command{ Use: app, Short: "a cross-platform command-line tool for safely batch renaming files/directories via regular expression", Long: fmt.Sprintf(` -brename -- a practical cross-platform command-line tool for safely batch renaming files/directories via regular expression +brename: a practical cross-platform command-line tool for safely batch renaming files/directories via regular expression Version: %s @@ -897,7 +897,7 @@ Special replacement symbols: log.Info() } - if !opt.Quiet || opt.DryRun { + if (!opt.Quiet || opt.DryRun) && !opt.ListPath { log.Info(bold("Searching for paths to rename...")) log.Info() } @@ -908,7 +908,7 @@ Special replacement symbols: checkError(err) } } - if !opt.Quiet && !opt.DryRun { + if !opt.Quiet && !opt.DryRun && !opt.ListPath { fmt.Fprintf(os.Stderr, "\r %-78s\n", green("Done searching.")) } close(opCH) @@ -1231,7 +1231,7 @@ func walk(opt *Options, opCh chan<- operation, path string, depth int) error { if opt.MaxDepth > 0 && depth > opt.MaxDepth { return nil } - if !opt.Quiet && !opt.DryRun { + if !opt.Quiet && !opt.DryRun && !opt.ListPath { _path := path n := len(_path) if n > 78 { @@ -1255,7 +1255,7 @@ func walk(opt *Options, opCh chan<- operation, path string, depth int) error { // it's a directory files, err := os.ReadDir(path) if err != nil { - if !opt.Quiet && !opt.DryRun { + if !opt.Quiet && !opt.DryRun && !opt.ListPath { fmt.Fprintf(os.Stderr, "\n") } if !opt.IgnoreErr { diff --git a/screenshot/check-error.png b/screenshot/check-error.png new file mode 100644 index 0000000..64cc07e Binary files /dev/null and b/screenshot/check-error.png differ diff --git a/screenshot/dry-run.png b/screenshot/dry-run.png new file mode 100644 index 0000000..b1c2462 Binary files /dev/null and b/screenshot/dry-run.png differ diff --git a/screenshot/linux.png b/screenshot/linux.png deleted file mode 100644 index cdd862f..0000000 Binary files a/screenshot/linux.png and /dev/null differ diff --git a/screenshot/success.png b/screenshot/success.png new file mode 100644 index 0000000..bd1de27 Binary files /dev/null and b/screenshot/success.png differ diff --git a/screenshot/undo.png b/screenshot/undo.png new file mode 100644 index 0000000..a2a4f25 Binary files /dev/null and b/screenshot/undo.png differ diff --git a/screenshot/windows.png b/screenshot/windows.png deleted file mode 100644 index 04ba3b2..0000000 Binary files a/screenshot/windows.png and /dev/null differ