1

Im looking for a batch script to (recursively) rename a folder of files.. Example of the rename: 34354563.randomname_newname.png to newname.png

I already dug up the RegEx for matching from the beginning of the string to the first underscore (its ^(.*?)_ ), but cant convince Windows Batch to let me copy or rename using RegEx.

4 Answers4

3

From command-line prompt - without :

FOR /R %f IN (*.*) DO FOR /F "DELIMS=_ TOKENS=1,*" %m IN ("%~nxf") DO @IF NOT "%n" == "" REN "%f" "%n"

In batch file, double %:

FOR /R %%f IN (*.*) DO FOR /F "DELIMS=_ TOKENS=1,*" %%m IN ("%%~nxf") DO @IF NOT "%%n" == "" REN "%%f" "%%n"

EDIT: A new pure batch solution issuing following cases:

  • Path\File_name.ext => name.ext
  • Path\none.ext (does nothing)
  • Path\Some_file_name.ext => file_name.ext
  • Path\name.some_ext (does nothing)
  • Path\Some_file_name.some_ext => name.some_ext

Batch (remove ECHO to make it functional):

FOR /R %%f IN (*.*) DO CALL :UseLast "%%~f" "%%~nf"

GOTO :EOF

:UseLast
FOR /F "DELIMS=_ TOKENS=1,*" %%m IN (%2) DO IF "%%n"=="" (
    IF NOT "%~2"=="%~n1" ECHO REN %1 "%~2%~x1"
) ELSE CALL :UseLast %1 "%%n"
GOTO :EOF
LS_ᴅᴇᴠ
  • 10,823
  • 1
  • 23
  • 46
  • The OP hasn't stated long filenames are used, but it won't hurt to allow for them. Use `REN "%%f" "%%n"` at the end of the last code above. – foxidrive Sep 19 '13 at 10:35
  • @foxidrive Ups, missed that! Thanks! – LS_ᴅᴇᴠ Sep 19 '13 at 10:37
  • Perhaps this is unlikely, but a name like `test.a_b` would become `b`. – dbenham Sep 19 '13 at 13:32
  • Yes, I know. @Endoro issues this concern. – LS_ᴅᴇᴠ Sep 19 '13 at 13:41
  • Um - OP specifies "First underscore" so I'd argue that what's required is to lop off the part before the first underscore. Or may be, the specification is quite unclear. In any case, I'd suggest it would be Kosher to check that the proposed target filename doesn't already exist... – Magoo Sep 19 '13 at 15:40
3

avoid _ in the extension:

@ECHO OFF 
FOR /F "DELIMS=" %%A IN ('DIR /S /B /A-D *_*.*') DO FOR /F "TOKENS=1*DELIMS=_" %%B IN ("%%~NA") DO IF "%%~C" NEQ "" ECHO REN "%%~A" "%%~C%%~XA"

Look at the output and remove ECHO if it looks good.

Endoro
  • 37,015
  • 8
  • 50
  • 63
  • +1, Your solution will preserve the name after the first `_`. A name like `a_b_c_d.txt` will become `b_c_d.txt`, which may or may not be fine. See my answer for other alternatives. – dbenham Sep 19 '13 at 13:18
  • +1 Good idea using `ECHO` to easily preview results and easily commit them. – LS_ᴅᴇᴠ Sep 19 '13 at 14:09
  • I don't know batch script, but it worked as a `.cmd` only if I removed the `ECHO` before `REN`. – Daniel Cheung Feb 23 '16 at 13:46
  • @DanielCheung Yes, as I stated in my answer: "Look at the output and remove ECHO if it looks good." – Endoro Feb 23 '16 at 18:33
0

The standard windows shell doesn't have regex capabilities, and in fact it's extremely basic. But you can use powershell to do this.

I'm not very familiar with power shell, but this other question explains how to filter files: Using powershell to find files that match two seperate regular expressions

Community
  • 1
  • 1
Augusto
  • 28,839
  • 5
  • 58
  • 88
0

New Solution

There is an extremely simple solution using JREN.BAT, my new hybrid JScript/batch command line utility for renaming files and folders via regular expression search and replace.

Only rename files with one underscore:

jren "^[^_]+_([^_]+\.png)$" "$1" /s /i

Preserve everything after the first underscore:

jren "^.*?_" "" /s /fm "*.png"

Preserve everything after the last underscore:

jren "^.*_" "" /s /fm "*.png"


=========================================================

Original Answer

This can be done using a hybrid JScript/batch utility called REPL.BAT that performs regex search and replace on stdin and writes the result to stdout. All the solutions below assume REPL.BAT is somewhere within your PATH.

I intentionally put ECHO ON so that you get a log of the executed rename commands. This is especially important if you get a name collision: two different starting names could both collapse to the same new name. Only the first rename will succeed - the second will fail with an error message.

I have three solutions that differ only in how they handle names that contain more than 1 _ character.

This solution will only rename files that have exactly one _ in the name (disregarding extension). A name like a_b_c_d.txt would be ignored.

@echo on&@for /f "tokens=1,2 delims=*" %%A in (
  '2^>nul dir /b /s /a-d *_* ^| repl ".*\\[^_\\]*_([^_\\]*\.[^.\\]*)$" "$&*$1" a'
) do ren "%%A" "%%B"

The next solution will preserve the name after the last _. A name like a_b_c_d.txt would become d.txt

@echo on&@for /f "tokens=1,2 delims=*" %%A in (
  '2^>nul dir /b /s /a-d *_* ^| repl ".*_([^\\_.]*\.[^.\\]*)$" "$&*$1" a'
) do echo ren "%%A" "%%B"

This last solution will preserve the name after the first _. A name like a_b_c_d.txt would become b_c_d.txt. This should give the same result as the Endoro answer.

@echo on&@for /f "tokens=1,2 delims=*" %%A in (
  '2^>nul dir /b /s /a-d *_* ^| repl ".*\\[^\\]*?_([^\\]*\.[^.\\]*)$" "$&*$1" a'
) do echo ren "%%A" "%%B"
Community
  • 1
  • 1
dbenham
  • 127,446
  • 28
  • 251
  • 390
  • You are using such heavy weapons for such a simple task. If JScript is to be used, a single JScript file would suffice, instead of 2 bat and 1 js. Mine solution (and @Endoro one) if run twice or more times would achieve same result. In my opinion, even a simple cycle inside batch would be better than this solution. – LS_ᴅᴇᴠ Sep 19 '13 at 13:45
  • @LS_dev - The REPL.BAT is a handy utility that can be used in a great many scenarios. Sure, it wouldn't make sense to develop it for just this, but once you have it, why not use it? Yes, you could achieve all three results using pure batch, or a single JScript or VBS. But once you have REPL.BAT in your arsenal, the coding is simpler. There is nothing wrong with your or Endoro's solution if you want to get my last result. But running multiple times to get my 2nd solution is not practical. How are you to know how many runs are required? You could add a FINDSTR with regex to get my first result. – dbenham Sep 19 '13 at 14:02
  • I recognize your merit for writing `REPL.BAT`. But as a handy utility, and for sake of efficiency, I would prefer [sed](http://gnuwin32.sourceforge.net/packages/sed.htm). Better 1 exe than 1 bat > 1 exe > 1 js and back. – LS_ᴅᴇᴠ Sep 19 '13 at 14:16
  • yes, nice `REPL` tool, and fast too. But your Regex doesn't work for files without extension. I don't know, if this is an real issue . – Endoro Sep 19 '13 at 15:02
  • @Endoro - Yes, works only with extension as written. Slight change to regex can handle names without extension: Use `?` after the literal dot, plus probably need `+` after one of the terms to guarantee at least one character after the `_`. – dbenham Sep 19 '13 at 15:18
  • @LS_dev - Yes, sed is a good solution for those that have permission to install 3rd party executable. I do not have that luxury at work, hence my development of REPL.BAT that is pure script, and it runs on all Windows machines from XP onward. – dbenham Sep 19 '13 at 15:21
  • You don't need to install sed, just place binaries and libraries in path. – LS_ᴅᴇᴠ Sep 19 '13 at 15:26
  • @LS_dev - Yes, physically I can do that, but policy forbids that at my office. – dbenham Sep 19 '13 at 15:28
  • One short question please: do you think you can enable [Character Class Subtraction](http://msdn.microsoft.com/en-us/library/ms994330.aspx) in `Repl.BAT`, [also mentioned here](http://stackoverflow.com/q/339763/2098699) ? – Endoro Sep 19 '13 at 19:33
  • @Endoro - Interesting - I hadn't run across that syntax. I'm using the JScript RegExp object, which does not support character class subtraction (CCS). I suppose the CCS could be pre-processed into a normal character class using appropriate ranges, but the parsing rules sound difficult. Not something I'm interested in pursuing. – dbenham Sep 19 '13 at 22:22