1

As the title says, I'm trying to pick up to four random files (wallpapers) from a folder, for further processing. The folder does not contain subfolders, just *.jpg's, *.bmp's and *.png's (it may contain a Thumbs.db file, but I already took care of that).

I read all the files with a for loop making something similar to an array, then I'd like to run another for loop for making the random numbers that will act as indexes for choosing the files.

setlocal enabledelayedexpansion
set "wps=1 2 3 4"
set /a ind = 0

for /f "tokens=* delims=" %%g in ('dir C:\Wallpapers /a:-h-s /b /s') do (
    set /a ind += 1
    set "!ind!=%%g"
)

for %%g in (%wps%) do (
    set /a "num = (((!random! & 1) * 1073741824) + (!random! * 32768) + !random!) %% %ind% + 1"
    echo Wallpaper %%g is #!num! - Title: "!!num!!"
)


Of course the line that echoes just outputs Wallpaper 1 is #118 - Title: "118" instead of Wallpaper 1 is #118 - Title: "C:\Wallpapers\Miami Skyline.jpg".

So my specific question is: how can I double expand a variable inside a for loop?

[Note #1: the line that creates the random number needs to be so long because it gives a good random distribution of values]
[Note #2: I need wps to be stored that way, because sometimes I could need just three wallpapers, not necessarily in numerical order]

Marco
  • 87
  • 3
  • 11

2 Answers2

1

Transfer the !num! value to a FOR variable :-)

for %%N in (!num!) do echo Wallpaper %%g is #%%N - Title: "!%%N!"

A few additional pointers:

  • As written, your DIR command is including folders. You need to add the /A-D option

    dir C:\Wallpapers /a:-h-s-d /b /s

  • Your numeric variable names work in your existing code. But you will have fits if you ever try to access them using normal expansion because %1% will expand as the 1st batch argument instead of the environment variable. In general practice you should avoid beginning an environment variable with a number. You could use:

    set wp!ind!=%%g
    ...
    echo Wallpaper %%g is #!num! - Title: "!wp%%N!

  • You can make your array 0 based by incrementing your counter at the bottom of the loop instead of the top. Then you don't need to add one to your random number. (This tip is trivial. More a matter of style.)

  • You don't need both "tokens=*" and "delims=". I recommend the latter. "delims=" will keep the entire string. tokens=* will keep the entire string after it strips leading spaces and tabs. A file name can begin with spaces.

  • Your code will fail if any of the file names contain ! characters. The exclamation will be corrupted during expansion of %%g because of delayed expansion. It is fairly easy to fix by toggling delayed expansion on and of and using a FOR variable to transfer the value across the ENDLOCAL barrier.

Here is the code with all of the recommendations in place

@echo off
setlocal disableDelayedExpansion
set "wps=1 2 3 4"
set /a ind = 0

for /f "tokens=* delims=" %%g in ('dir C:\Wallpapers /a:-h-s-d /b /s') do (
  setlocal enableDelayedExpansion
  for %%N in (!ind!) do (
    endlocal
    set "wp%%N=%%g"
  )
  set /a ind += 1
)

setlocal enableDelayedExpansion
for %%g in (%wps%) do (
  set /a "num = (((!random! & 1) * 1073741824) + (!random! * 32768) + !random!) %% %ind%"
  for %%N in (!num!) do echo Wallpaper %%g is #%%N - Title: "!wp%%N!"
)
dbenham
  • 127,446
  • 28
  • 251
  • 390
  • Thanks for the suggestions and the final code, helps a lot and everything is crystal clear.One note: the first `setlocal disableDelayedExpansion` (second line) could be omitted, right?Also, I'd prefer having a 1-starting array, as my file manager numbers files from 1. The first `for` loop then reads`for /f "tokens=* delims=" %%g in ('dir C:\Dati\Marco\Documenti\ /a:d /b') do ( set /a ind += 1 setlocal enableDelayedExpansion for %%N in (!ind!) do ( endlocal set "wp%%N=%%g" ) )` (notice the swapping of setting ind and the delayedexpansion) – Marco Jun 11 '12 at 13:47
0

You could use another FOR like dbenham suggested or you could use CALL

call echo Wallpaper %%g is #!num! - Title: "%%!num!%%"

A CALL expands a line a second time, but only the percent expansion, neither delayed nor FOR-loop expansion works in the second reparse of the line.

EDIT: This only works, if the content of num doesn't begin with a number.

But you could use cmd /c to expand a second time, then it works also with numeric names.

cmd /c echo Wallpaper %%g is #!num! - Title: "%%!num!%%"
jeb
  • 78,592
  • 17
  • 171
  • 225
  • 1
    Except it will fail because the variable name is numeric! Obviously the names should be changed to include an alpha prefix. – dbenham Jun 11 '12 at 11:37
  • Yes you are right, I missed that, but you could solve it with `cmd /c` then – jeb Jun 11 '12 at 11:40