Windows batch file renames filename unexplainably

2019-07-18 11:59发布

Windows batch file renames filename unexplainably in FOR loop

I have a small Windows 7 batch file to rename a library of MP3 filenames. I've included only the last few lines of code in this question. It works fine except one problem with the section of code that appends a string of text (artist name) from a variable to each filename in the directory. (Once solved, my batch file will use "set /p var=" to prompt for text to fill the variable.)

Two sample filenames used for this test are:

01-serious song.mp3
02-happy song.mp3

This section of code results in a problem:

@echo off
setlocal enabledelayedexpansion
::Temporay test variable
set str=Artist-
for %%a in (*.mp3) do (
  set oldName=%%a
  set newName=!str!!oldName!
  ren "!oldName!" "!newName!"
)
endlocal

The result is that the 02 file ends up with the string appended once (as intended), while the 01 filename gets the string appended twice (error):

Artist-Artist-01-serious song.mp3
Artist-02-happy song.mp3

I've combed the Internet and not found one discussion of this happening. And I hate to say that I've spent about 8 hours working on it myself. After many tests and research, I believe that the rename statement was somehow causing this.

So I changed the batch file to call a subroutine with the rename command in it, thinking it was interferring with the for statement. That still had the problem. Then I edited the batch file with echo commands as shown below to test it.

Version Two Test:

@echo off
setlocal enabledelayedexpansion
set str=Artist-
for %%a in (*.mp3) do (
set oldName=%%a
set newName=!str!!oldName!
  call :Action
echo.
echo back in For loop
)
echo.
echo For loop completed
echo !oldName!
echo !newName!
endlocal
goto:eof

:Action
echo.
echo start of Action loop
echo !oldName!
echo !newName!
ren "!oldName!" "!newName!"
echo end of Action loop

Here is the resulting output shown on the CMD screen:

start of Action loop
01-serious song.mp3
Artist-01-serious song.mp3
end of Action loop

back in For loop

start of Action loop
02-happy song.mp3
Artist-02-happy song.mp3
end of Action loop

back in For loop

start of Action loop
Artist-01-serious song.mp3
Artist-Artist-01-serious song.mp3
end of Action loop

back in For loop

For loop completed
Artist-01-serious song.mp3
Artist-Artist-01-serious song.mp3

This was interesting as it showed the subroutine properly being called and returned twice. Then it somehow got called a third time, where it apparently renamed the 01 file again, appending the variable a second time.

If I put echo before the ren statement, then the screen output shows the subroutine is only called twice, but it doesn't rename the files, of course. I also tried using the move command instead of rename, and got the same problem result.

So, my question is, Why is the for loop calling the subroutine three times and making the 01 file get processed twice, and how can I make it to work as intended?

Thank you, Pete.

标签: windows cmd
2条回答
forever°为你锁心
2楼-- · 2019-07-18 12:26

replace this:

for %%a in (*.mp3) do (
  set oldName=%%a
  set newName=!str!!oldName!
  ren "!oldName!" "!newName!"
)

with that:

for /f "delims=" %%a in ('dir  /b /a-d *.mp3') do (
  set "oldName=%%~a"
  set "newName=%str%!oldName!"
  ren "!oldName!" "!newName!"
)

I can explain this later, if you want so, but Peter was faster :)

查看更多
Animai°情兽
3楼-- · 2019-07-18 12:28

Try

for /f "delims=" %%a in (' dir /b /a-d *.mp3') do (

The problem is that your original syntax finds the next filename - which finds your renamed file since the new filename (with the prefix) is logically 'greater than' the old.

Using dir builds a list of filenames, and processes the list once it has been completely built - hence the list doesn't vary as the files are renamed.

The "delims=" clause ensures that the default parsing of the filename is ineffective - otherwise, the filename would be interpreted as a series of [space-separated] tokens.

查看更多
登录 后发表回答