Randomly select a line out of a text file and set that line as a variable -
how randomly select line/ip out of text file, , set variable.
i mean like:
set ip=theline/ipfromofthefile
the array based solutions seem ought fastest because read file once. variable manipulation becomes slow when environment becomes large. array based solutions give non-linear performance. can painfully slow if file large.
for pure batch based solution gives decent linear performance, regardless of file size, aschipfl's answer. however, has problems lines begin ;
due default /f eol value. fails if file empty. here corrected version perfect.
@echo off setlocal set "file=test.txt" set "line=" /f %%n in ( 'type "%file%" ^| find /c /v ""' ) set set /a rnd=%random% %% %%n 2>nul || goto :break if %rnd%>0 (set "skip=skip^=%rnd%") else set "skip=" /f usebackq^ %skip%^ delims^=^ eol^= %%l in ("%file%") ( set "line=%%l" goto :break ) :break set line
there 1 remaining flaw above - if selected line empty, return next non-empty line instead due design of /f.
the "standard" way fix use findstr prefix each line line number, , use expansion find/replace remove prefix. given presence of line number prefix, use additional findstr select correct line, rather relying on /f
@echo off setlocal set "file=test.txt" set "ln=" /f %%n in ( 'type "%file%" ^| find /c /v ""' ) set /a rnd=%random% %% %%n + 1 2>nul || goto :result /f "delims=" %%l in ( 'findstr /n "^" "%file%" ^| findstr "^%rnd%:"' ) set "ln=%%l" setlocal enabledelayedexpansion set "ln=!ln:*:=!" :result set ln
if know lines <= 1021 bytes long, there simpler solution dealing empty lines reads file set /p instead of /f.
@echo off setlocal set "file=\utils\jrepl.bat" set "ln=" /f %%n in ( 'type "%file%" ^| find /c /v ""' ) set /a rnd=%random% %% %%n 2>nul || goto :result <"%file%" ( /l %%n in (1 1 %rnd%) set /p "ln=" set "ln=" set /p "ln=" ) :result set ln
just yucks, decided write solution based on jrepl.bat regular expression text processing utility. optimized hybrid jscript/batch script written, jrepl convenient if have in bag of tricks.
if need print random line, simple 1 liner:
call jrepl "^.*" $0 /c /jmatch /jbeg "rnd=math.floor(math.random()*cnt)+1" /jbegln "skip=(rnd!=ln)" /f test.txt
a bit more code needed value in variable:
@echo off setlocal set "ln=" /f "delims=" %%l in ( 'jrepl "^.*" $0 /c /n 1 /jmatch /jbeg "rnd=math.floor(math.random()*cnt)+1" /jbegln "skip=(rnd!=ln)" /f test.txt' ) set "ln=%%l" setlocal enabledelayedexpansion set "ln=!ln:*:=!" :result set ln
if lines <= 1021 , don't mind temp file, use set /p
@echo off setlocal call jrepl "^.*" $0 /c /jmatch /jbeg "rnd=math.floor(math.random()*cnt)+1" /jbegln "skip=(rnd!=ln)" /f test.txt /o temp.txt set "ln=" <temp.txt set /p "ln=" del temp.txt :result set ln
Comments
Post a Comment