Notes › Tech Notes › Pad Width Is Only a Floor: Where (2) Lands When a Batch Rename Hits 2000 Files

Pad Width Is Only a Floor: Where (2) Lands When a Batch Rename Hits 2000 Files

I ran a rename script and only afterwards found two files sharing one name. Another batch went in with a serial width of 3 and came back carrying 6 names of 8 characters. The rule did not fail: the constraint printed on the form and the rule that executes are two different objects, and the surprises on this page sit in that gap.

I lifted the relevant functions out of the batch rename template and ran them alone, row by row. The landing points are narrow: the width you set is a floor, the collision number lands between base name and extension, and a row you retype by hand joins no avoidance pass. Nothing reaches your disk until you run what you export.

The width you set is a floor, not a ceiling

The column labelled 序号位数 carries min="0" max="9" and looks bounded. What runs is only brPad, in the template since T300, and it holds one branch: prepend zeros when the digits fall short, leave them alone when they overshoot. brPad(999,3) gives 999, and brPad(10000,3) gives 10000. Nothing clips, nothing warns.

Attributes on a form field have no authority over its script, so I pushed values the form would refuse. pad=9 hands me 000000001.jpg, typing 12 hands me 000000000001.jpg, and typing a negative two is not even rejected: the width is compared with the length of the number and the padding simply never fires.

Batch / widthCharacter length spreadHow to read it
105 files / pad=299 names at 6 characters, 6 names at 7From 100 onward the whole column gets wider
1005 files / pad=3999 names at 7 characters, 6 names at 8After 999 there is room for one more digit
12 files / pad=1212 names at 16 charactersThe max=9 printed on the form is not enforced
1005 files, pad=3 7 chars 999 8 chars 6 Fig. 1: padding adds zeros, never truncates

The middle row is the ordinary case: almost the whole batch sits at one length and a thin remainder one character longer, and no branch can make a name shorter than you asked. The last row is the loud one, since a dozen files given a twelve digit width come out with twelve zeros in front.

Duplicate names: the number lands before the extension

The conflict control sits on auto. When many rows point at one name it raises no error, skips nothing and overwrites nothing already there: the later one becomes base name, a space, (2), then the dot and suffix exactly as that row had them, stamped 重名,已自动追加编号. Forcing all 50 rows into one name left the last line reading same.txt (50).txt with only 49 rows carrying the note, because the first arrival never moves. Inserting instead of appending shows on compound extensions: after a collision a.b.tar.gz comes out as x.tar.gz (2).gz.

Case folds in the comparison only. toLowerCase makes Photo.jpg / PHOTO.JPG / photo.jpg one hole, and the escaped row keeps the case it typed, giving same.txt (2).JPG. The other setting, skip, writes 重名,已保持原名 and leaves the duplicate for whichever shell runs your export.

Two exceptions: the row you edited and the row you switched off

An in-table edit goes through brEditRow (T561-571), which refreshes the statistics bar and the script but never calls brDedupe. I typed p.txt into both the p.txt and the q.txt row: the table showed two identical names at once, the export accepted both, and the single Rename-Item -LiteralPath 'q.txt' -NewName 'p.txt' line points at a name already on disk. Only the next rule change reruns the pass, and only then does that row become p (2).txt.

Switching off 改名 does not release a row from the ledger either: it stops producing a new name yet keeps its original claimed in advance. With x.txt and b.txt, find x replaced by b and the b.txt row switched off, the surviving x.txt is pushed to b (2).txt.

Both sit on a page that writes back to disk 0 times, with no undo, no redo and no history in the template. The rename happens when you run the exported ps1, bat or sh against real files.

Four rulings about the extension

brSplitName knows one split point, the last dot: a.tar.gz is base a.tar plus extension gz, while a leading dot name such as .gitignore is ruled to have no extension and keeps its dot. Case never crosses that line: choosing 全部小写 turns DSC Photo JPG.jpeg into dsc-photo-jpg.jpeg and leaves the trailing .jpeg alone, and lowering the suffix takes 统一小写, picked separately.

Without 连扩展名一起替换 the replacement only sees the base name, so find \..* with an empty repl still leaves a.gz standing, because the original suffix is read back onto the end, and a literal find of .gz changes nothing until that checkbox is on. The reverse trap is choosing 强制指定 for the extension with a blank value: Photo.JPG and doc.pdf come out as Photo and doc, and those stripped names are not counted in the 规则有问题 statistic either.

A $ inside the replacement is not a literal

Once 按正则处理 is on, repl follows JS replacement semantics. Find b with repl $`X turns abc.jpg into aaXc.jpg, since the slice before the match is pasted in whole; $&$& gives abbc.jpg; and $9 with no ninth group leaves the dollar sign in the name, giving a$9c.jpg. In literal mode those strings are plain text.

A broken pattern does not take the page down. brReplace returns a sentinel string (T395), the row shows 正则表达式写错了 and keeps its original name, and the cost lands elsewhere: every row judged broken is left out of the export. With 3 files and find written as (, all 3 rows stay red, the bar reads 规则有问题:3, the export holds 0 rows, the script box is empty, and packing answers 没有可导出的文件.

The cap, and the limits sitting beside it

The page takes 2000 files at most. I dropped 2005 in: files recorded 2000, the table held 2000 rows, and the preview drew only the first 400 of them, closing with a line saying another 1600 rows were not shown. Rename-Item, ren and mv -n each came out with 2000 commands, and the export was 2000 lines as well.

After dropping 2005 files Preview rows 400 Export rows 2000 Script lines 2000 Fig. 2: counted in full past the preview

Three further numbers bound what a name may become. The base name has a hard top at 160 characters: a 204 character original is cut to 160, the suffix is reattached and the finished name is 164 characters long, with the row saying the name was too long and got cut to 160. Windows reserved names run to 22 entries, CON, PRN, AUX and NUL plus COM and LPT from 1 to 9, and a hit gets an underscore in front, while CONSOLE.txt and LPT10 are not judged. Illegal characters are deleted when cleaning is checked and swapped for underscores when it is not, yet the note claims removal either way.

Three questions I was asked on the spot

Q: If I set the width too small, are longer names truncated?

They are not. brPad only prepends zeros, so 1005 files at pad=3 still leave 6 names of 8 characters. The one truncation here sits on the base name at the 160 character top, not on the width field.

Q: After I edit a row by hand, does the collision pass still run?

Not at that moment. brEditRow never calls brDedupe, so two identical rows can reach the export together until the next rule change rewrites one as p (2).txt. Pressing any template button takes the unconditional assignment at T679-683 and recomputes your hand edits with nothing to restore them.

Q: Will the exported batch file stop by itself on a duplicate name?

The header promises it, but the .bat I got holds @echo off, chcp 65001 >nul, a rem header and one ren per row, 13 lines in all, with no errorlevel, no if exist and no exit anywhere. On a clash ren prints one error line and the commands after it carry on. The construct that really refuses to overwrite is mv -n in the sh export; quoting and interruption I walked through once in the batch mkdir script note.

One pass before you run what you exported

  • Sort the target column and look for repeats, since the rows you typed by hand joined no avoidance pass.
  • Check the length spread of the serial column: pad=3 mixed with names of 8 characters is a carry, not a lost setting.
  • If you force an extension, give the field a value; blank deletes the suffix from every name.
  • With regex on, read the broken rule count down to nothing, since those rows never reach the export, and check any replacement starting with $ against the regex testing basics note.

One habit matters more than the rest: treat that export as a review of real files. This page changes nothing on its own, which makes it easy to forget that running the script turns those names into the state of your folder with nothing to come back through. Sort the column, read the notes, keep the original listing, and only then run it.

📎 Related articles

Same 70 Bytes, 13 MIME Types: file-info Reads the Extension, Never the Content 2026-10-23 My Transparent Logo Came Back as a White JPG, and 91 Quality Levels Changed Nothing on the PNG Side 2026-10-23 Remove Everything Still Left 553 Bytes, and Location Only Never Touched the Thumbnail 2026-10-23 Two Certificate Fingerprints, 95 Characters and 64: The Missing 31 Are All Colons 2026-10-23 My TOTP Code Was One Window Behind: What a ±1 Step Back-Check Can and Cannot Tell You 2026-10-23