Opening random file from folder AND subfolders with batch script (Windows 7)

2

1

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

Posted 2015-01-31T17:37:05.120

Reputation: 31

Answers

6

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

Posted 2015-01-31T17:37:05.120

Reputation: 9 212

Well I had marked this as the solution, but I realized that the first time I use the (first) script, it indeed opens a random file from a random subfolder, BUT the next few times I use it it opens random files from ONLY that same subfolder. Sometimes it will move on to another random folder, but again start opening files from that folder only. Pretty weird... I suppose this is not the intended behavior? – Cesar – 2015-02-01T21:44:52.550

@Cesar - It depends on how you are running the script. If you launch the script from Windows Explorer or a shortcut each time, then you will see that behavior. But if you run the script repeatedly within the same console window, then the results will be good. It is a limitation of the batch %random% function related to how it is seeded. See http://stackoverflow.com/questions/19694021/random-generator-in-the-batch for an explanation. In particular, the answers from me and MC-ND.

– dbenham – 2015-02-01T22:08:46.147

I'm sorry, I don't know how to run it "repeatedly from the same console window". – Cesar – 2015-02-02T03:19:39.687

@Cesar - Launch the cmd.exe console: From the Start menu, select "All Programs", then "Accessories", then "Command Prompt". CD to the folder where your script resides, then enter the name of the script. As long as your script does not have the EXIT command, then you can run it repeatedly. EXIT /B is OK, but EXIT kills the console. – dbenham – 2015-02-02T03:37:09.840

1

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.

MC ND

Posted 2015-01-31T17:37:05.120

Reputation: 1 286