jfgoodhew1
jfgoodhew1

Reputation: 95

Read file path from dir list in text file and store as variable in batch script Windows

The purpose is to select a single folder at random from within a given text file containing a folder list using a batch script in Windows.

Step by step method:

  1. input home directory path
  2. check current drive letter and change drive letter to match homedir drive if necessary
  3. change directory to home directory
  4. write dir list to text file HOMEDIR.TXT in home directory
  5. set SKIP variable to a random number up to the number of lines in that text file EVERYTHING WORKS UP TO THIS POINT
  6. For loop with no delimiters (so I get the whole line) and skip %SKIP% number of lines. Then do set VARNAME=%%I from the for loop. Then goto NextLine so it's not repeated until the end of the text file. ***THIS STEP GIVES ME ERROR: System cannot find file specified.

[EDIT] On further testing, error only happens IF %SKIP% > 4 i.e. if SKIP corresponds to a line with a filepath on it, it gives that error. Else it works fine.

I've read all the answers everywhere, but can't solve it! If I take the for outside into a test file with just random words it works fine. So I can only presume it's something to do with the special characters in the dir output list that are causing problems? Any help much appreciated!

My Code:

:: Make the code run quietly
@ECHO OFF

:: Get home directory
set HOMEDIR=D:\External\My Pictures

:: Switch to the drive of HOMEDIR
:: If the drive letter of the current directory differs from HOMEDIR
:: Then change drive letter
:: Else change directory to root of that drive
:: Thanks Jatrim for if not http://stackoverflow.com/questions/1421441/batch-not-equal-operator
if not %cd:~0,2% == %HOMEDIR:~0,2% %HOMEDIR:~0,2% else cd %HOMEDIR:~0,2%

:: Change directory to HOMEDIR
cd "%HOMEDIR%"

:: Write a list of the subdirectories of HOMEDIR to file homedir.txt
dir "%cd%" /a:d >> homedir.txt

:: Calculate how many lines there are in homedir.txt
:: Thanks Aacini from http://stackoverflow.com/questions/13343144/random-line-of-text-ussing-batch
for /F "" %%I in (homedir.txt) do set /a LINES=%%I
echo LINES=%LINES%

:: enable delayed expansion (needed???)
setlocal EnableDelayedExpansion

:: Set a random integer (within the limit of variable LINES)
:: Thanks Aacini from http://stackoverflow.com/questions/13343144/random-line-of-text-ussing-batch
set /a SKIP=%random%%%LINES%
echo SKIP=%SKIP%

:: In homedir.txt the first 5 lines aren't directories
:: SKIP THESE LINES SOMEHOW

:: Thanks Andriy M for the inspiration! http://stackoverflow.com/questions/6409869/echo-the-nth-line-from-a-text-file-where-n-is-a-command-line-argument
:: If it's the same as SKIP, read line's contents into variable SCRDIR

for /F "usebackq delims= skip=%SKIP%" %%I in (homedir.txt) do (if not defined SCRDIRORIG set SCRDIRORIG=%%I & GoTo :NextLine)
pause
:NextLine
echo %SCRDIRORIG%
pause

Upvotes: 0

Views: 2741

Answers (3)

MC ND
MC ND

Reputation: 70971

For a version without temporary files you can try with

@echo off
    setlocal enableextensions disabledelayedexpansion

    set "HOMEDIR=D:\External\My Pictures"

    for /f "tokens=1,*" %%a in ('
        cmd /q /v /c"for /d %%a in ("!HOMEDIR!\*") do (set /a "1000000000+(!random! * %random% %% (!random!+1^)^)" & echo( %%a)"
        ^| sort
        ^| cmd /q /v /c"(set /p "line^=" & echo(!line!)"
    ') do set "SCRDIRORIG=%%b"

    echo Folder selected : %SCRDIRORIG%

The code creates a cmd instance that will list all the folders under the indicated starting point prefixed with a random number. This list is sorted and then the first line in the list retrieved.

All this is wrapped inside a for /f command so at the end we can separate the starting random number from the folder name and set the variable.

Upvotes: 0

user1016274
user1016274

Reputation: 4209

I've tried to carefully select the means for each step in the following code in order to avoid pitfalls.

  1. Although changing to the HOMEDIR is not strictly necessary here it is best done with a cd /d which changes the drive as well if necessary.
  2. the list of folders can be created quickly so creating a temp file can be avoided. Using dir /b /ad does not include '.' and '..' nor any junctions like dir /ad would.
  3. For counting, use of find /c combined with a negated search for the empty string yields the count directly without need for complicated extraction (or loops).
  4. We need a random number of lines to skip in the range 0..nlines-1 . One method is to apply the modulus operator (%) but it might fail if nlines is 0. So the alternative method is used. The quotient %RANDOM% / 32768 is in the desired range [0..1) so we only need to multiply it with nlines.
  5. You have to test for zero lines to skip, otherwise the FOR loop will choke on the skip= option.
  6. The final FOR loop extracts the desired line and stops immediately with a GOTO. Not nice but effective.

Here is the code:

@echo off &setlocal enableextensions

set "HOMEDIR=D:\External\My Pictures"

cd /d %HOMEDIR%
:: count the dirs
for /f %%I in ('dir /b /ad "%HOMEDIR%"^| find /c /v ""') do set "nlines=%%I"
:: pick a number from 0..nlines-1
set /A nskip=%random% * %nlines% / 32768
:: discard "skip=" option if no lines to skip
set skipopt=
if %nskip% GTR 0 set skipopt=skip=%nskip%
:: read line[nskip+1] from input and quit
for /F "%skipopt% delims=" %%I in ('dir /b /ad %HOMEDIR%') do set "LINE=%%I" & GOTO :out
:out
echo folder selected : %LINE%

Upvotes: 0

Endoro
Endoro

Reputation: 37589

I would recommend this:

    @echo off &setlocal disabledelayedexpansion
    for /f "tokens=1*delims=:" %%a in ('findstr /n $ homedir.txt') do (
        set ".%%~a.=%%~b"
        set /a DirCount=%%~a
    )
    set /a DirCount-=5
    set /a Sample=%random%%%DirCount
    set /a Sample+=5
    for /f "tokens=1*delims==" %%a in ('set ".%Sample%."') do echo %%~b

Upvotes: 2

Related Questions