Nested for loop recursing directories

91 views
Skip to first unread message

GlennG

unread,
Sep 16, 2010, 1:20:50 AM9/16/10
to
HI

I am writing a batch (win7) to recurse folders in my music collection to
manipulate particular files.

I have a folder structure:

D:\Music\Genre\Artist\Album\title.mp3

Starting in music folder, I have three nested for loops, code below.

The problems are:
a, non alphanumeric characters stuff up the change directory
b, it moves up the directory tree after the first genre

Any help would be appreciated. I have always wanted to learn the batch
language.

Cheers
Glenn


@echo off
cls
set thisdir=%cd%

:: parse genres folder
for /f "delims=" %%A in ('dir /b /ad') do (
cd "%%~nA"
echo Genre: %%A

:: parse artists
for /f "delims=" %%B in ('dir /b /ad') do (
cd "%%~nB"
echo Artist: %%B

:: parse albums
for /f "delims=" %%C in ('dir /b /ad') do (
cd "%%~nC"
echo Album: %%C
cd ..
)
cd ..
)
cd ..
)

cd /d "%thisdir%"

foxidrive

unread,
Sep 16, 2010, 1:54:36 AM9/16/10
to
On 16/09/2010 15:20, GlennG wrote:

> I am writing a batch (win7) to recurse folders in my music collection to
> manipulate particular files.
>
> I have a folder structure:
>
> D:\Music\Genre\Artist\Album\title.mp3
>

Can you explain what you need to do?

Your approach might be the right one, or it might not depending on the task.


Mic

GlennG

unread,
Sep 16, 2010, 2:02:17 AM9/16/10
to

What I want to do is move the folder.jpg from the last album up to the
artist folder so that it shows up in my media center. There is possibly
a better way of doing this, but I've wanted to learn how to use
iteration in batch files for ages. I have approx 4000 albums.

foxidrive

unread,
Sep 16, 2010, 2:22:08 AM9/16/10
to

I need some clarification...

The task is to move folder.jpg from each album folder into the artist
folder?
Will folder.jpg be a unique name?

EG if artist1 has album1 album2 album3 will each album have a folder.jpg ?


--
Regards,
Mic

mazellan

unread,
Sep 16, 2010, 3:47:12 AM9/16/10
to

Yes, the file is folder.jpg, and each album will have its own
folder.jpg. I was just going to copy them from oldest to latest album,
overwriting the copied file in the artist folder, so I will end up
with the latest album's artwork. My album folders all start with the
year, ie. 1889 Mozart's Greatest Hits
The idea is the iteration takes me to each album in turn where I do
someting like:
copy /y folder.jpg ..

foxidrive

unread,
Sep 16, 2010, 4:02:52 AM9/16/10
to
On 16/09/2010 17:47, mazellan wrote:
> On Sep 16, 4:22 pm, foxidrive<foxidr...@gotcha.woohoo.invalid> wrote:
>> On 16/09/2010 16:02, GlennG wrote:
>>
>>
>>
>>> foxidrive wrote:
>>>> On 16/09/2010 15:20, GlennG wrote:
>>
>>>>> I am writing a batch (win7) to recurse folders in my music collection to
>>>>> manipulate particular files.
>>
>>>>> I have a folder structure:
>>
>>>>> D:\Music\Genre\Artist\Album\title.mp3
>>
>>>> Can you explain what you need to do?
>>
>>>> Your approach might be the right one, or it might not depending on the
>>>> task.
>>
>>>> Mic
>>
>>> What I want to do is move the folder.jpg from the last album up to the
>>> artist folder so that it shows up in my media center. There is possibly
>>> a better way of doing this, but I've wanted to learn how to use
>>> iteration in batch files for ages. I have approx 4000 albums.
>>
>> I need some clarification...
>>
>> The task is to move folder.jpg from each album folder into the artist
>> folder?
>> Will folder.jpg be a unique name?
>>
>> EG if artist1 has album1 album2 album3 will each album have a folder.jpg ?
>>
>
> Yes, the file is folder.jpg, and each album will have its own
> folder.jpg. I was just going to copy them from oldest to latest album,
> overwriting the copied file in the artist folder, so I will end up
> with the latest album's artwork. My album folders all start with the
> year, ie. 1889 Mozart's Greatest Hits
> The idea is the iteration takes me to each album in turn where I do
> someting like:
> copy /y folder.jpg ..


In that scenario then this should work.

@echo off
for /f "delims=" %%a in ('dir folder.jpg /b /s') do (
pushd "%%~dpa"
copy /y folder.jpg ..
popd
)


--
Regards,
Mic

mazellan

unread,
Sep 16, 2010, 5:18:17 AM9/16/10
to

Thanks Mic that works great.

billious

unread,
Sep 16, 2010, 8:53:23 AM9/16/10
to

"GlennG" <mazel...@hotmail.com> wrote in message
news:OOhko.55934$u16....@newsfe17.iad...


Fundamental syntax error.

"::" is a broken label used for convenience as a comment.

You can't use labels WITHIN a FOR loop.

Change the comments within the loop to REM and you'll see a difference.....


jeb

unread,
Sep 16, 2010, 1:53:03 PM9/16/10
to
billious wrote:

> Fundamental syntax error.
>
> "::" is a broken label used for convenience as a comment.
>
> You can't use labels WITHIN a FOR loop.
>
> Change the comments within the loop to REM and you'll see a difference.....

Ok, "::" is a label without a name, so you can not call it, but you
can use it as comment.

You can use labels WITHIN a for loop or generally in paranthesis
blocks, but it is not allowed to place it at the end.
It is also possible to call/jump to this labels, it's a bad idea (a
goto stops the loop), but it works.

billious

unread,
Sep 16, 2010, 2:24:20 PM9/16/10
to

"jeb" <xi...@gmx.de> wrote in message
news:bc60bf58-40a4-48fc...@a11g2000vbn.googlegroups.com...

You appear to be correct. I've had trouble with the "::" comments in a loop
before and cured them with a change to REM - hadn't done an in-depth
investigation...


Frank P. Westlake

unread,
Sep 18, 2010, 9:01:54 AM9/18/10
to
"billious" news:mvCdnTAcqJxK_Q_R...@westnet.com.au...

> I've had trouble with the "::" comments in a loop before and cured
> them with a change to REM ...

Me also; I think MS must have fixed this with a service pack. Because of
the original state it is still better to avoid '::' within parentheses.

Frank


I'm_HERE

unread,
Sep 18, 2010, 9:11:09 AM9/18/10
to
bug with REM:
-----------------------

REM %~
echo test1

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

REM %^
echo test2

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

REM. >FILE
echo test3


bug with ::
---------------

(
echo test1
::commentaire
::commentaire
echo test2
)


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

for %%a in (test 3) do (
echo %%a
:: test3
)

foxidrive

unread,
Sep 18, 2010, 9:21:52 AM9/18/10
to
On 18/09/2010 23:11, I'm_HERE wrote:
> bug with REM:
> -----------------------

This is an issue with %~ being incompatible with the %~0 syntax.

> REM %~
> echo test1
>
> =============


This one uses the ^ as the end of line continuation character so it is
effectively just a rem'ed line.

> REM %^
> echo test2
>
> ============


This has always been an issue with REM when including < > | etc.
That's why :: was superior.

> REM.>FILE
> echo test3
>

> bug with ::
> ---------------

This is interesting. Remove one of the lines and it works normally.

> (
> echo test1
> ::commentaire
> ::commentaire
> echo test2
> )
>

Here is the behaviour of a label inside a loop. If you use :test3 it
will do the same thing.


> ==============
>
> for %%a in (test 3) do (
> echo %%a
> :: test3
> )


Thanks for your post. It exercised my grey matter. :)

--
Regards,
Mic

I'm_HERE

unread,
Sep 18, 2010, 9:36:00 AM9/18/10
to
Thanks for your post foxidrive

see this

for %%i in (test 3) do (
echo %%i
:: comment
)

and

for %%i in (test 3) do (
:: comment
echo %%i

)

foxidrive

unread,
Sep 18, 2010, 10:11:57 AM9/18/10
to
On 18/09/2010 23:36, I'm_HERE wrote:
> Thanks for your post foxidrive
>
> see this
>
> for %%i in (test 3) do (
> echo %%i
> :: comment
> )
>
> and

I see. The placement of the :: affects the result.

> for %%i in (test 3) do (
> :: comment
> echo %%i
>
> )
>


--
Regards,
Mic

jeb

unread,
Sep 18, 2010, 3:00:05 PM9/18/10
to
foxidrive wrote:

This is an issue with %~ being incompatible with the %~0 syntax.

> REM %~
> echo test1

Yes the %~ is generally not allowed, but why the REM or :: are not
able to remark it and avoid the error.

It is an issue that the percent phase is before the "REM" is detected.
The interpreter phases are explained also in
http://groups.google.co.uk/group/alt.msdos.batch.nt/msg/057272ca12daa629

But now I get confused
(
:: comment
echo work
)

(
:: comment

echo This one fails
)

(
:: comment ^

FehlerError echo You see this, but why?
)


jeb

foxidrive

unread,
Sep 18, 2010, 4:25:53 PM9/18/10
to
On 19/09/2010 05:00, jeb wrote:
> foxidrive wrote:
>
> This is an issue with %~ being incompatible with the %~0 syntax.
>
>> > REM %~
>> > echo test1
> Yes the %~ is generally not allowed, but why the REM or :: are not
> able to remark it and avoid the error.

A REMark line is parsed by cmd and command.com and which is why
redirection characters are also verboten.


--
Regards,
Mic

jeb

unread,
Sep 18, 2010, 5:06:15 PM9/18/10
to
foxidrive wrote:
> A REMark line is parsed by cmd and command.com and which is why
> redirection characters are also verboten.

Not at all.

rem. > File
creates a file

but

rem > File
remarks the complete line

rem & echo This does not work
rem\ echo nix & echo But this one

It's because the REM is detected in the second phase of the
interpreter, but only if it is typed the correct way.
If it is detected it disables the rest of the line (not correct for
carets at all but that's not the subject).

If the token does not match in phase 2, the rest of the line is
interpreted regulary with ^&|<>.
But later the rem is detected, and remark in this example the "echo
nix"

jeb

Timo Salmi

unread,
Sep 19, 2010, 2:40:22 AM9/19/10
to
On 18.09.2010 16:21 foxidrive <foxi...@gotcha.woohoo.invalid> wrote:
> On 18/09/2010 23:11, I'm_HERE wrote:
>> bug with REM:
> This is an issue with %~ being incompatible with the %~0 syntax.

>> REM %~
>> echo test1

There is some incomplete information and links to earlier discussions in
48} Why do some comment lines cause errors? What can I do about it?
http://www.netikka.net/tsneti/info/tscmd048.htm

All the best, Timo

--
Prof. Timo Salmi mailto:t...@uwasa.fi ftp & http://garbo.uwasa.fi/
Hpage: http://www.uwasa.fi/laskentatoimi/english/personnel/salmitimo/
Department of Accounting and Finance, University of Vaasa, Finland
Useful CMD script tricks http://www.netikka.net/tsneti/info/tscmd.php

foxidrive

unread,
Sep 19, 2010, 4:08:46 AM9/19/10
to
On 19/09/2010 07:06, jeb wrote:
> foxidrive wrote:
>> A REMark line is parsed by cmd and command.com and which is why
>> redirection characters are also verboten.
>
> Not at all.
>
> rem.> File
> creates a file
>
> but
>
> rem > File
> remarks the complete line

Not so in MSDOS V6.22

It's changed since msdos but it's still a fact that REM cannot be used
as robustly as :: with the character set.


--
Regards,
Mic

Timo Salmi

unread,
Sep 19, 2010, 5:10:11 AM9/19/10
to
On 19.09.2010 11:08 foxidrive wrote:
>> foxidrive wrote:
>>> A REMark line is parsed by cmd and command.com and which is why
>>> redirection characters are also verboten.

Except for the special sake of the group's interest, the main advice is
to avoid remarks within constructs. That anso explains the
(
)
parsing phenomenon. It probably boils down to why so many
if (
)
and
for (
)
constructs elicit confusion and questions from the users.

One can't quite second-guess the interpreter. :-)

All the best, Timo

--
Prof. Timo Salmi mailto:t...@uwasa.fi ftp & http://garbo.uwasa.fi/
Hpage: http://www.uwasa.fi/laskentatoimi/english/personnel/salmitimo/
Department of Accounting and Finance, University of Vaasa, Finland

Useful script files and tricks ftp://garbo.uwasa.fi/pc/link/tscmd.zip

jeb

unread,
Sep 19, 2010, 1:25:03 PM9/19/10
to
Timo Salmi wrote:
> parsing phenomenon. It probably boils down to why so many
> if (
> )
> and
> for (
> )
> constructs elicit confusion and questions from the users.
>
> One can't quite second-guess the interpreter. :-)
>
> All the best, Timo

I suppose my explanation of the batchline parser (without paranthesis)
is nearly complete.
My aim is to be able to understand the complete interpreter, not only
to say don't use this, sometimes it does not work.

jeb

billious

unread,
Sep 19, 2010, 10:44:04 PM9/19/10
to

"jeb" <xi...@gmx.de> wrote in message
news:c31856b1-7e41-45ab...@t11g2000vbc.googlegroups.com...

A fine ambition indeed.

Problem is that different versions have different rules - in fact Frank's
comment seems to indicate that we have different behaviour within well- who
knows? It might be one OS version and different service packs, or it might
be an incremental fix silently distributed as part of the constant stream of
fixes. There's no information apparently easily available about what
particular KBxxxx fixed what particular problem.

Or attempted to fix, as seems more like the case.

I believe that the best we can do is to indeed say to avoid particular
constructs because they're unreliable and weather the pleadings of those
well-intentioned programmers whose systems don't exhibit the error.


Frank P. Westlake

unread,
Sep 22, 2010, 8:55:28 AM9/22/10
to
"jeb"
news:f2368619-9650-4c50...@l17g2000vbf.googlegroups.com...

> But now I get confused

Method 1:

> (
> :: comment
> echo work
> )

Method 2:

> (
> :: comment
>
> echo This one fails
> )


Method 3:

> (
> :: comment ^
>
> FehlerError echo You see this, but why?
> )

Methods 1 and 3 above are the same. The result of the escape character
(^) in method 3 makes it:

(
:: comment


FehlerError echo You see this, but why?
)

But any confusion is justified in this case and I think required in all
cases to be able to write CMD script.

Frank


jeb

unread,
Sep 25, 2010, 2:11:50 PM9/25/10
to

Method3 is not only different by the "^" caret, also the empty line is
important.

But my confusion is nearly gone, as you can see here.

@echo off
set :=^%=~0%
%=~dp0%
echo=%=~%
<:echo call :%%%% <nul ^
set five=three,one & ^
echo two
(
echo three
%:~% ^
echO five
:label
:%:~t0^
:label^
:\..\%~nx0 & echo one & Echo hhh
:ds^
:label%:%four & rem ^
echo=%4
:xy
:\..\%~nx0 & call :~%%%%
)

I suppose, the code need not to be explained, it is obvious :-)

jeb

foxidrive

unread,
Sep 25, 2010, 2:25:48 PM9/25/10
to
On 26/09/2010 04:11, jeb wrote:
> But my confusion is nearly gone, as you can see here.
>
> @echo off
> set :=^%=~0%
> %=~dp0%
> echo=%=~%
> <:echo call :%%%%<nul ^
> set five=three,one& ^

> echo two
> (
> echo three
> %:~% ^
> echO five
> :label
> :%:~t0^
> :label^
> :\..\%~nx0& echo one& Echo hhh
> :ds^
> :label%:%four& rem ^
> echo=%4
> :xy
> :\..\%~nx0& call :~%%%%

> )
>
> I suppose, the code need not to be explained, it is obvious :-)
>
> jeb

I await the comments. :)


--
Regards,
Mic

Frank P. Westlake

unread,
Sep 29, 2010, 9:23:33 AM9/29/10
to
"jeb"
news:80106717-ee56-4b00...@h13g2000yqa.googlegroups.com...

> Frank P. Westlake wrote:
>> Method 3:
>>
>> > (
>> > :: comment ^
>> >
>> > FehlerError echo You see this, but why?
>> > )

> Method3 is not only different by the "^" caret, also the empty line is
> important.

It is important when within parentheses? Normally it is not but I don't
recall testing it within parentheses. Without the parentheses the escape
character escapes either the <CR> or the <LF> -- I think I recall that
it is <CR> -- so the line

"LINE 1<CR><LF>LINE 2" becomes
"LINE 1<LF>LINE 2", or perhaps
"LINE 1<CR>LINE 2".

So my statement that 1 and 3 are identical is not true. The appearance
might be the same but the strings may be different.

> But my confusion is nearly gone, as you can see here.

<Script removed>

> I suppose, the code need not to be explained, it is obvious :-)

From just looking at the script I can follow the first half but I have
not seen before what you are doing with labels so I cannot follow the
rest. Unfortunately I won't have the time necessary to examine it so I
hope you will provide a description of the general behavior of the
labels as you are using them.

And thanks for joining us Jeb.

Frank


jeb

unread,
Sep 30, 2010, 12:02:48 PM9/30/10
to

Frank P. Westlake schrieb:

Ok. I try to explain it a bit.

The code
set :=^%=~0%
%=~dp0%
echo=%=~%

is only for obfuscation, as the variable %=~0% and %=~dp0% can't
exists and so it will be replaced with nothing.
So you get
set :^

echo=
The blank line is important, because the caret ^ will produce in the
variable ":" a "<Linefeed>echo=".

The next block is only one command line (and also a legal label!)


<:echo call :%%%% <nul ^
set five=three,one & ^
echo two

As command line, it is the same as call :%%%% set five=three,one
<:echo <nul & echo two
The <:echo redirection will be removed, because only the last
redirection for a given stream number will be active, all other are
removed without recognizing the syntax.
As a call statement cause to parse the line two times, the search will
be for the label ":%"

The label is in this example ":%:~t0^ " because the label searcher
does not expand anything, and the name of a label stops at a :<space>
or +, the caret at this line is unimportant, because a call will
always start the code at the next line after the label.

The next line is a label with a caret at the end so the the parser
interpetes (and ignores) it as


:label^
:\..\%~nx0 & echo one & Echo hhh

--->
":label :\..\%~nx0 & echo one & Echo hhh"


Then comes also a label with a caret so you get for the lines (and
expanding the %:% var)


:ds^
:label%:%four & rem ^
echo=%4

":ds:label<LineFeed>echo= four & rem ^"
So why it stops at the end of line 2 with "rem ^" ?
Because there is a linefeed in the line, outside of blocks the parser
stops parsing at linefeeds.

"echo=%4"
And it will print %4="one" (call :%%%% set five=three,one ) %1=set
%2=five %3=three %4=one

The next two lines are normal labels and they will be ignored, and it
runs to the end, returning to the "caller"


:xy
:\..\%~nx0 & call :~%%%%

The caller was the line "call :%%%% set five=three,one <:echo <nul &
echo two "
So the "two" is printed (by the ampersand)

Now the block is completly scanned and cached, as
(
echo three
echo=four & remecho=
& call :~%%
)

But why?
(
Ok --- echo three
Label with caret --- %:~% ^
Caret from the last line --- echO five

A normal label --- :label
Label with caret --- :%:~t0^
Caret from the last line --- :label^
Caret from the last line --- :\..\%~nx0 & echo one & Echo hhh
Secondary label with caret ---:ds^
Caret from the last line, BUT Linefeed --- :label%:%four & rem ^
*** Expands to two lines --- :label
*** the rem with caret consumes the next line --- echo=four & remecho=
%4

A normal label --- :xy
Secondary label!!! --- :\..\%~nx0 & call :~%%%%
*** Secondary label expands to --- & call :~%
)

Ok, two significant new items are here.
1. A linefeed in a paranthesis block does not stop the parsing, it
splits the line into two lines
2. Each label has a requires secondary line, the secondary line can be
a normal command or also a label,
but the first part of a label have to be a legal commdand. And an
ampersand works in a the secondary label line!
That's the cause why it seems, that a label is not allowed at the at
of a block.
(
echo hello
:this Fails
)

But only the secondary line is the problem, in this case the ")"
(
echo hello
:first label
:secondary label
)

jeb

Frank P. Westlake

unread,
Oct 2, 2010, 9:02:37 AM10/2/10
to
"jeb"
news:618cde8b-a489-4645...@i5g2000yqe.googlegroups.com...

> Ok. I try to explain it a bit.

Thank you very much for your effort in that explanation; and in
English -- isn't German your native language? I will have to save it and
study it when I have electricity on a daily basis -- perhaps late next
month. Right now I only have two days each week on the laptop and the
rest of the time I use a handheld (Archos 5).

Frank


jeb

unread,
Oct 5, 2010, 11:20:30 AM10/5/10
to
Ok, I understand, my english is really bad :-(
And yes, german is my native language.

I try this, because my main interesst in batch is to understand all
the possiblities, tricks and failures.
To write programs, batch isn't my first choice.

jeb

Frank P. Westlake

unread,
Oct 6, 2010, 9:46:52 AM10/6/10
to
"jeb"
news:41578ea9-f9fd-4d6a...@n3g2000yqb.googlegroups.com...

> Ok, I understand, my english is really bad :-(
> And yes, german is my native language.


I wasn't complaining about your English -- I was praising it. Here is my
German:

That was it; if you read too fast you might have missed it.

Frank


Reply all
Reply to author
Forward
0 new messages