Windows batch file - Pick (up to) four random files in a folder

二次信任 提交于 2019-12-11 07:57:15

问题


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]


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



回答2:


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


来源:https://stackoverflow.com/questions/10978107/windows-batch-file-pick-up-to-four-random-files-in-a-folder

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!