批处理文件中的随机数不会改变

批处理文件中的随机数不会改变

如何使此脚本在命令提示符下工作?目前所有随机数都是相同的

SET SOME[1]="AA"
SET SOME[2]="BB"
SET SOME[3]="CC"
SET SOME[4]="DD"
SET SOME[5]="EE"
FOR /L %%i IN (1,1,5) DO FOR /F %%j IN ('SET RND=%%RANDOM%%*5/32768+1') DO ECHO SOME[%%i] %%j

答案1

哇 - 你那一小段代码有很多问题:-)

您发布的代码缺少 SET /A 选项。我假设您的实际代码有该选项。

代码因语法错误而失败的原因是 FOR IN() 子句中的命令是通过命令执行的cmd /C yourCommandHerecmd /C解析隐式命令时,=除非对其进行转义或引用,否则它将被视为标记分隔符。在使用命令行语义在新的 CMD 线程中实际执行命令之前,任何连续的标记分隔符字符串都会转换为单个。<space>标记分隔符列表为, ; = <space> <non-breaking space><tab>

因此引用该命令将消除语法错误:

FOR /L %%i IN (1,1,5) DO FOR /F %%j IN ('SET /A "RND=%%RANDOM%%*5/32768+1"') DO ECHO SOME[%%i] %%j

正如将逃避=

FOR /L %%i IN (1,1,5) DO FOR /F %%j IN ('SET /A RND^=%%RANDOM%%*5/32768+1') DO ECHO SOME[%%i] %%j

但您实际上并不需要将随机数分配给变量。 FOR IN() 命令在命令行上下文中执行,而 SET /A 在命令行上下文中运行时会将计算值打印到 stdout。因此,以下操作也可以消除任何语法错误,并产生相同的结果:

FOR /L %%i IN (1,1,5) DO FOR /F %%j IN ('SET /A %%RANDOM%%*5/32768+1') DO ECHO SOME[%%i] %%j

以下是一个更简单的方法来给出从 1 到 5 的结果(随机模 5 + 1):

FOR /L %%i IN (1,1,5) DO FOR /F %%j IN ('SET /A %%RANDOM%% %% 5 + 1') DO ECHO SOME[%%i] %%j

但我严重怀疑上述任何修复是否能达到您想要的结果。

的值发生了一些非常奇怪的事情%RANDOM%。正确使用%%RANDOM%%会导致每次迭代都对表达式进行求值。但由于某种原因,随机数对于任何给定的运行几乎是恒定的。偶尔,其中一次迭代会有所不同,但对于大多数运行,每次迭代都会获得一个常数值。我认为这一定与随机数生成器种子值有关。也许每次启动 CMD 会话时,随机数生成器都会用种子值启动,并且种子值只会非常缓慢地变化。请记住,FOR IN() 子句是在新的 CMD 会话中执行的。

这是一个测试程序,它演示了%%test%%每次迭代时都会正确地重新评估。它还显示了%%random%%在运行过程中如何保持几乎恒定。

@echo off
setlocal
set test=0
for /l %%I in (1 1 5) do for /f "delims=" %%J in ('echo %%test%% %%random%%') do (
  echo %%J
  set "test=%%I
)

以下是上述代码两次运行的输出。请注意第一次运行的随机数有一个变化。第二次运行的随机数为常数。

C:\test> test
0 20369
1 20373
2 20373
3 20373
4 20373

C:\test> test
0 20379
1 20379
2 20379
3 20379
4 20379

确实没有理由将随机数计算放在 FOR /F IN('command') 子句中。如果直接在外循环中使用带有延迟扩展的 SET /A,一切都会变得简单得多。

我相信以下内容可能就是您正在寻找的:

@echo off
setlocal enableDelayedExpansion
SET SOME[1]="AA"
SET SOME[2]="BB"
SET SOME[3]="CC"
SET SOME[4]="DD"
SET SOME[5]="EE"
FOR /L %%i IN (1,1,5) DO (
  set /a rand=!random!%%5+1
  for %%N in (!rand!) do echo %%i: SOME[%%N]=!SOME[%%N]!
)

以下是一些示例输出:

C:\test>test
1: SOME[3]="CC"
2: SOME[5]="EE"
3: SOME[2]="BB"
4: SOME[2]="BB"
5: SOME[5]="EE"

编辑

这里有更好的证据表明,CMD 会话的随机器被重新播种,并且种子变化缓慢。

@echo off
setlocal enableDelayedExpansion

echo Within a single CMD session, every ^^!random^^! gets a new value.
for /l %%N in (1 1 10) do call echo !time! !random! !random!

echo(

setlocal disableDelayedExpansion
echo But each CMD session !random! is reseeded,
echo and the seed only changes once per second,
echo and the inital value changes slowly:
for /l %%N in (1 1 30) do cmd /v:on /c "echo !time! !random! !random!&for /l %%A in (1 1 50000) do @rem"

- 输出 -

Within a single CMD session, every !random! gets a new value.
11:12:10.37 17810 1733
11:12:10.37 8919 24464
11:12:10.37 9931 2137
11:12:10.37 28574 16630
11:12:10.37 30379 23234
11:12:10.37 22410 31740
11:12:10.38 15479 14080
11:12:10.38 812 23616
11:12:10.38 1384 25909
11:12:10.38 2733 1947

But each CMD session !random! is reseeded,
and the seed only changes once per second,
and the inital value changes slowly:
11:12:10.39 4552 6316
11:12:10.50 4552 6316
11:12:10.61 4552 6316
11:12:10.71 4552 6316
11:12:10.82 4552 6316
11:12:10.92 4552 6316
11:12:11.03 4555 17064
11:12:11.14 4555 17064
11:12:11.24 4555 17064
11:12:11.35 4555 17064
11:12:11.45 4555 17064
11:12:11.56 4555 17064
11:12:11.67 4555 17064
11:12:11.77 4555 17064
11:12:11.88 4555 17064
11:12:11.99 4555 17064
11:12:12.09 4559 27813
11:12:12.20 4559 27813
11:12:12.30 4559 27813
11:12:12.41 4559 27813
11:12:12.51 4559 27813
11:12:12.62 4559 27813
11:12:12.73 4559 27813
11:12:12.83 4559 27813
11:12:12.94 4559 27813
11:12:13.04 4562 5793
11:12:13.15 4562 5793
11:12:13.26 4562 5793
11:12:13.36 4562 5793
11:12:13.47 4562 5793

答案2

%RANDOM%由于您在循环中扩展变量FOR,因此需要使用延迟扩展。

这会产生 5 个相同数字的回声:

FOR /L %%i IN (1,1,5) DO (
echo %random%
)

这会产生 5 个“随机”数:

setlocal ENABLEDELAYEDEXPANSION

FOR /L %%i IN (1,1,5) DO (
echo !random!
)

您可以通过运行来找到有关延迟扩展的更多信息

SET /?

答案3

在这种情况下您需要delayed expansion

echo off & setlocal enabledelayedexpansion
set test=0
for /l %%I in (1 1 5) do for /f "delims=" %%J in ('echo !test! !random!') do (
  echo %%J
  set "test=%%I"
)

这比 更快%%test%%。输出示例:

0 26542
1 32475
2 25609
3 4495
4 6719

这也有效(较慢):

echo off & setlocal enabledelayedexpansion
set test=0
for /l %%I in (1 1 5) do for /f "delims=" %%J in ('cmd /v:on /c echo !test! !random!') do (
  echo %%J
  set "test=%%I"
)

但下面的操作不起作用:

echo off & setlocal
set test=0
for /l %%I in (1 1 5) do for /f "delims=" %%J in ('cmd /v:on /c echo !test! !random!') do (
  echo %%J
  set "test=%%I"
)

0 19919
1 19919
2 19919
3 19919
4 19919

相关内容