如何从文本文件中随机选择一行/ ip,并将其设置为变量。
我的意思是:
set IP=TheLine/IPFromOfTheFile
答案 0 :(得分:3)
基于阵列的解决方案似乎应该是最快的,因为它们只读取一次文件。但是当环境变得非常大时,变量操作变得非常慢。因此,基于阵列的解决方案可提供非线性性能。如果文件非常大,它们可能会非常慢。
对于基于纯批处理的解决方案,无论文件大小如何,都能提供良好的线性性能,我喜欢aschipfl's answer。但是,由于/ f EOL值的默认值,以;
开头的行存在问题。如果文件为空,它也会失败。这是一个几乎完美的修正版本。
@echo off
setlocal
set "file=test.txt"
set "LINE="
for /F %%N in (
'type "%file%" ^| find /C /V ""'
) do set set /A RND=%RANDOM% %% %%N 2>nul || goto :BREAK
if %RND%>0 (set "skip=skip^=%RND%") else set "skip="
for /F usebackq^ %skip%^ delims^=^ eol^= %%L in ("%file%") do (
set "LINE=%%L"
goto :BREAK
)
:BREAK
set LINE
上面还有一个缺陷 - 如果所选行为空,那么由于FOR / F的设计,它将返回下一个非空行。
"标准"解决方法是使用FINDSTR为每行添加行号,然后使用扩展find / replace来删除前缀。鉴于行号前缀的存在,我喜欢使用额外的FINDSTR来选择正确的行,而不是依赖于FOR / F
@echo off
setlocal
set "file=test.txt"
set "ln="
for /f %%N in (
'type "%file%" ^| find /c /v ""'
) do set /a rnd=%random% %% %%N + 1 2>nul || goto :result
for /f "delims=" %%L in (
'findstr /n "^" "%file%" ^| findstr "^%rnd%:"'
) do set "ln=%%L"
setlocal enableDelayedExpansion
set "ln=!ln:*:=!"
:result
set ln
如果您知道所有行都是< = 1021字节长,那么有一个更简单的解决方案来处理使用SET / P而不是FOR / F读取文件的空行。
@echo off
setlocal
set "file=\utils\jrepl.bat"
set "ln="
for /f %%N in (
'type "%file%" ^| find /c /v ""'
) do set /a rnd=%random% %% %%N 2>nul || goto :result
<"%file%" (
for /l %%N in (1 1 %rnd%) do set /p "ln="
set "ln="
set /p "ln="
)
:result
set ln
只是为了好运,我决定根据我的JREPL.BAT regular expression text processing utility编写一个解决方案。可以编写一个优化的混合JScript /批处理脚本,但如果你已经把它放在你的技巧包中,那么JREPL很方便。
如果您只需要打印一条随机线,那么它就是一个简单的衬垫:
call jrepl "^.*" $0 /c /jmatch /jbeg "rnd=Math.floor(Math.random()*cnt)+1" /jbegln "skip=(rnd!=ln)" /f test.txt
需要更多代码才能获得变量中的值:
@echo off
setlocal
set "ln="
for /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'
) do set "ln=%%L"
setlocal enableDelayedExpansion
set "ln=!ln:*:=!"
:result
set ln
如果这些行都是&lt; = 1021并且您不介意临时文件,那么您可以使用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
答案 1 :(得分:2)
首先,您需要知道文本文件textfile.txt
中出现的行数:
for /F %%N in ('type "textfile.txt" ^| find /C /V ""') do set NUM=%%N
然后计算从0
到NUM-1
的范围内的随机数:
set /A RND=%RANDOM%%%NUM
最后从文本文件中选择一行并将其存储在LINE
中。 RND
保存for /F
循环要跳过的行数:
if %RND% EQU 0 (set "SKIP=") else (set "SKIP=skip=%RND% ")
for /F "usebackq %SKIP%delims=" %%L in ("textfile.txt") do (
set "LINE=%%L"
goto :NEXT
)
:NEXT
这依赖于文本文件不包含任何空行的事实。
答案 2 :(得分:1)
@echo off
setlocal EnableDelayedExpansion
rem Load file lines into "line" array
set "num=0"
for /F "usebackq delims=" %%a in ("theFile.txt") do (
set /A "num+=1"
set "line[!num!]=%%a"
)
rem Select one random line
set /A "rnd=%random% %% num + 1"
set "IP=!line[%rnd%]!"
echo %IP%
有关批处理文件中阵列管理的更多详细信息,请参阅this post。
答案 3 :(得分:1)
如果我早些时候接受过这个问题,我可能会写出Aacini的答案。他从我那里获得+1。
无论如何,对于一些不同的东西怎么样?这是一个调用PowerShell帮助程序的批处理单行程序。
for /f "delims=" %%I in ('powershell "get-random (gc \"%file%\")"') do set "IP=%%I"
它比Aacini的解决方案慢,但它确实具有简单的优势。 *耸肩*如果你的IP文件包含任何空行,你可以添加一个选择器,只包括真实性不评估为false / empty的行。
for /f "delims=" %%I in ('powershell "gc \"%file%\" | ?{$_} | get-random"') do set "IP=%%I"
我还考虑过使用find /c /v "" txtfile
然后使用for /f "skip=%randomLineNumber%"
来获取文本文件中的行数(就像aschipfl的回答一样),但是效率已经低于其他答案了提供。
答案 4 :(得分:0)
试试这个:
@echo off
setlocal EnableDelayedExpansion
set "file=somefile.txt"
set "lines=0"
for /F "usebackq delims=" %%a in ("%file%") do set /a "lines+=1"
set /a "selected=%random%%%%lines%"
set "lines=0"
for /F "usebackq delims=" %%a in ("%file%") do (
if !lines! equ !selected! set "line=%%a"
set /a "lines+=1"
)
echo %line%
pause
答案 5 :(得分:-2)
我的解决方案基本上与Aacini相同,但有一些不同的细节:
@echo off
setlocal enabledelayedexpansion
set i=0
for /f "tokens=*" %%x in (%1) do (
set line[!i!]=%%x
set /a i += 1
)
set /a j=%random% %% %i%
set ip=!line[%j%]!
文件名是此批次的参数。