4

I want to get a bat file that will open a random file (with any extension) from a specific folder, but also open files in all subfolders within that folder. There's another question that asked something like this (How do I open a random file in a folder, and set that only files with the specified filename extension(s) should be opened?), and provided this script:

@echo off & setlocal
 :: start of main
 rem Set your path here:
 set "workDir=C:\DVDCOVERS"

 rem Read the %random%, two times is'nt a mistake! Why? Ask Bill.
 rem In fact at the first time %random% is nearly the same.
 @set /a "rdm=%random%"
 set /a "rdm=%random%"

 rem Push to your path.
 pushd "%workDir%"

 rem Count all files in your path. (dir with /b shows only the filenames)
 set /a "counter=0"
 for /f "delims=" %%i in ('dir /b ^|find "."') do call :sub1

 rem This function gives a value from 1 to upper bound of files
 set /a "rdNum=(%rdm%*%counter%/32767)+1"

 rem Start a random file
 set /a "counter=0"
 for /f "delims=" %%i in ('dir /b ^|find "."') do set "fileName=%%i" &call :sub2

 rem Pop back from your path.
 popd "%workDir%"

 goto :eof
 :: end of main

 :: start of sub1
 :sub1
 rem For each found file set counter + 1.
 set /a "counter+=1"
 goto :eof
 :: end of sub1

 :: start of sub2
 :sub2
 rem 1st: count again,
 rem 2nd: if counted number equals random number then start the file.
 set /a "counter+=1"
 if %counter%==%rdNum% (start "" "%fileName%")
 goto :eof
 :: end of sub2

 :: -snap--- end of batch

Source: http://forums.majorgeeks.com/showthread.php?t=181574

However, this script only opens files located in the main folder and none from the subfolders. I'm sure the fix is a simple one but I can't figure it out. Help is much appreciated, thanks.

Cesar
  • 51

2 Answers2

9

Not only does this code randomly open a file anywhere within the folder hierarchy, it is also more efficient than the original:

@echo off
setlocal

:: Create numbered list of files in a temporary file
set "tempFile=%temp%\%~nx0_fileList_%time::=.%.txt"
dir /b /s /a-d %1 | findstr /n "^" >"%tempFile%"

:: Count the files
for /f %%N in ('type "%tempFile%" ^| find /c /v ""') do set cnt=%%N

call :openRandomFile

:: Delete the temp file
del "%tempFile%"

exit /b

:openRandomFile
set /a "randomNum=(%random% %% cnt) + 1"
for /f "tokens=1* delims=:" %%A in (
  'findstr "^%randomNum%:" "%tempFile%"'
) do start "" "%%B"
exit /b

By default the script will look for files under the current directory, but you can pass a root path as the first argument, and it will start looking there instead.

The code is more efficient when opening just one file, but it really shows improvement if you want to open multiple files, since it only needs to generate the list once. It is also more efficient to let FINDSTR find the selected file instead of looping through the entire list.

I structured the code to make it easy to open multiple random files. Below I randomly select 25, and print out the command to open them. Simply remove the ECHO to actually open the files:

@echo off
setlocal

:: Create numbered list of files in a temporary file
set "tempFile=%temp%\%~nx0_fileList_%time::=.%.txt"
dir /b /s /a-d %1 | findstr /n "^" >"%tempFile%"

:: Count the files
for /f %%N in ('type "%tempFile%" ^| find /c /v ""') do set cnt=%%N

:: Open 25 random files
for /l %%N in (1 1 25) do call :openRandomFile

:: Delete the temp file
del "%tempFile%"

exit /b

:openRandomFile
set /a "randomNum=(%random% %% cnt) + 1"
for /f "tokens=1* delims=:" %%A in (
  'findstr "^%randomNum%:" "%tempFile%"'
) do echo start "" "%%B"
exit /b
dbenham
  • 11,794
2

While the code in dbenham's answer is what i would use, just for an alternative

@echo off
    setlocal enableextensions disabledelayedexpansion

    set "rootFolder=C:\DVDCOVERS" 

    for /f "usebackq tokens=1,* delims=:" %%a in (`
        cmd /q /v /e /c "for /f delims^= %%a in ('dir /a-d /s /b "%rootFolder%"') do echo(!random!:%%a"
        ^| sort 2^>nul
        ^| cmd /q /e /v /c "set /p ".^=" & echo(!.!"
    `) do start "" "%%~b"

The code works in the following way:

  1. Executes a recursive dir command.
  2. For each file in the list, echoes the name of the file and a random number.
  3. Sorts the list of files. As it is prefixed with a random number, the order is random.
  4. From the list, the first file is retrieved.
  5. The retrieved record is split, discarding the initial random number and starting the selected file.

And yes, it is CPU-intensive as, for it to work, one sort command and four cmd instances are started.

Hashim Aziz
  • 13,835
MC ND
  • 1,561