IoCalisto
IoCalisto

Reputation: 53

How to properly use rename (ren) in Batch

I am trying to rename every image in a directory to add the date that each file was created, however, I keep either getting "invalid syntax" or "A duplicate file name exists, or the file cannot be found"

I am running Windows 10, and accessing the images off a flash drive (hence the short file path). I tried having all the code in one for-loop, when that didn't work I tried using batch functions, no dice. I did see someone mention on another thread to use delayed expansion, I would be up for using this if someone could give a better explanation than the /? command.

@echo off

REM batch file is placed in top of F drive, same as "images 2017+"

cd "F:\images 2017+"
FOR /R "F:\images 2017+" %%F in (*.jpg) do call :renER "%%~nF" "%%~tF" 
goto :eof
:renER
cd "F:\images 2017+"
pause
echo %1
echo %2

rename %1.jpg %1_%2.jpg
pause
goto :eof

:end

For every .jpg file in "images 2017+", the date which that file was created would be stuck onto the end after a space.

thisIsMyFile.jpg made at 5-13-2017, would become thisIsMyFile 5-13-2017.jpg

Current output

EDIT:

I am CDing into the same directory as the images are, then using the passed variables to locate the correct image (The date is one of the passed variables, and shows up in the echo command).

Upvotes: 1

Views: 2792

Answers (3)

Ben Personick
Ben Personick

Reputation: 3264

I notice that you only want the date, not the time so you can do that as follows using your existing Call to a label, There is also no need to use FOR /R in this case so I'll use a normal for loop:

@echo off
FOR %%A IN ("F:\images 2017+\*.jpg") DO (
  CALL :RenER "%%~fA" %%~tA
)
GOTO :eof
:RenER
  PAUSE
  ECHO %1
  ECHO %2
  SET "_tmp=%~2"
  SET "_tmp=%tmp:/=-"
  REN "%~1" "%~n1_%_tmp%%~x1"
  PAUSE
GOTO :eof

Notice how above we are dropping the Time off immediately by not wrapping it in quotes since you don't want that to be part of the file name.

You can also forgo the call to a label entirely without needing delayed expansion by using a second loop, as a matter of preference I think this is quite a bit cleaner!

@echo off
FOR %%A IN ("F:\images 2017+\*.jpg") DO (
  FOR /F "Tokens=1-3 Delims=/ " %%a IN ('echo.%%~tA') DO (
    PAUSE
    ECHO.%%~fA
    ECHO.%%~tA
    REN "%%~fA" "%%~nA_%%a-%%b-%%c%%~xA"
    PAUSE
  )
)

this is nice and clean and with a minor edit we can paste it directly into the CMD Prompt which is nicer still This is because we are not using DelayedExpansion, Calling a Label, or using Temp variables so by changing the %%s to %s, we can then Paste this directly into the CMD Line which is often more convenient when doing these sorts of operations:

This Multi-line will do just fine to be pasted into CMD directly:

FOR %%A IN ("F:\images 2017+\*.jpg") DO (
  FOR /F "Tokens=1-3 Delims=/ " %a IN ('echo.%~tA') DO @(
    PAUSE
    ECHO.%~fA
    ECHO.%~tA
    REN "%~fA" "%~nA_%a-%b-%c%~xA"
    PAUSE
  )
)

or, as a single line to paste into CMD if you prefer:

FOR %A IN ("F:\images 2017+\*.jpg") DO @( FOR /F "Tokens=1-3 Delims=/ " %a IN ('echo.%~tA') DO @( PAUSE& ECHO.%~fA& ECHO.%~tA& REN "%~fA" "%~nA_%a-%b-%c%~xA"& PAUSE ) )

Upvotes: 3

David
David

Reputation: 2272

@Stephan's answer is probably the best approach. But if you want to change directories ...

The windows shell has a working drive/volume, and on each drive/volume a current working folder. cd changes the working folder on a disk; to change the working folder on a drive (which is not the working drive) and to make that drive the working drive, you need to use cd /d, in this case cd /d "F:\images 2017+".
(A plain cd in this instance changes the working folder on F:\, but if your working folder is on C: -- as I'm guessing is the case -- it will not be changed.)

Assuming command extensions are enabled, you should also be able to use pushd and popd. pushd behaves like cd /d but also saves your previous location; popd returns you to that previous location. (And IIRC pushd will accept UNC paths.)
So at the beginning of your script, pushd "F:\images 2017+", and at the end popd.

I tend to favor pushd/popd over cd because invocations can be nested. So you can do things like (assume working directory is C:\Users\IoCalisto):

pushd "F:\images 2017+"
(working directory is now F:\images 2017+)

pushd "Z:\images 2015-2016"
(working directory is now Z:\images 2015-2016)

popd
(working directory is now F:\images 2017+)

popd
(working directory is now C:\Users\IoCalisto)

... with this approach, your scripts will have fewer "side effects" and be more modular, or at least modularizable.

Upvotes: 1

Stephan
Stephan

Reputation: 56180

no need to cd anywhere. ren takes a full path/filename for source - just the destination must be a filename only. So ... do call :renER "%%~fF" "%%~tF" is fine (no need to snip the extension and add it again later). In the subroutine reformat the time to a valid string and reassemble the destination file name:

@echo off
FOR /R "F:\images 2017+" %%F in (*.jpg) do call :renER "%%~fF" "%%~tF" 
goto :eof
:renER
pause
echo %1
echo %2
set "string=%~2"
set "string=%string::=-%"
set "string=%string:/=-"
ECHO rename "%~1" "%~n1_%string%%~x1"
pause
goto :eof

:end

NOTE: I disarmed the rename command. Remove the ECHO after troubleshooting, if it works as intended.

Upvotes: 1

Related Questions