سؤال

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]

هل كانت مفيدة؟

المحلول

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!"
)

نصائح أخرى

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!%%"
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top