如何使用批处理文件随机重新排列文本文件中的行

4
我正在编写一段代码,以随机方式遍历不同的MAC地址,但我无法想出如何实现。我考虑采用此脚本随机化或重新排列文本文件中的MAC地址,但我无法用批处理文件来实现这一点。它将读取"maclist.txt",然后创建一个新的临时文件"maclist_temp.txt",其中包含随机的顺序,即重新排列后的文件。然后,按顺序提取这个随机文件。
我已经尝试使用Google和搜索网页,但没有找到太有用的东西。我仍在积极寻找,但任何建议都将非常有用。
如提取和删除随机行,然后添加到底部等简单操作可能有效。但更好的方法是随机化,但我想保留原始列表。类似以下步骤:
1. 复制maclist.txt为maclist_temp.txt 2. 从maclist_temp.txt中随机选择一个MAC地址,并将其从文件中删除 3. 在文件底部重新添加
这就是我想要的全部内容,但欢迎提出任何建议。

你至少需要两个临时文件和一个嵌套的 for 循环。 - Monacraft
我不是在Linux上,我是Windows 7用户。另外,什么是嵌套的for循环? - computerlife22
@computerlife22 指的是一个循环内部嵌套了另一个循环。 - Dale
5个回答

7
你可以尝试使用这个批处理文件来帮助你打乱maclist.txt中的内容。该批处理文件的用法如下:batch file。请注意,html标签保留不变。
C:\> type list.txt | shuffle.bat > maclist_temp.txt

以下是shuffle.bat文件的内容:
@ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET TmpFile=tmp%RANDOM%%RANDOM%.tmp
TYPE NUL >%Tmpfile%
FOR /F "tokens=*" %%i IN ('MORE') DO SET Key=!RANDOM!!RANDOM!!RANDOM!000000000000& ECHO !Key:~0,15!%%i>> %TmpFile%
FOR /F "tokens=*" %%i IN ('TYPE %TmpFile% ^| SORT') DO SET Line=%%i&ECHO.!Line:~15!
::DEL %TmpFile%
ENDLOCAL

执行上述命令后,maclist_temp.txt将包含一个随机化的MAC地址列表。
希望这有所帮助。

5
这里有一种更简单的方法来随机化文件,不需要临时文件。你甚至可以重用相同的输入文件名。
限制是:空行和以“;”开头的行将被跳过,以“=”开头的行将剥离所有前导的“=”符号,并且“^”字符会被加倍。
@echo off
setlocal
for /f "delims=" %%a in (maclist.txt) do call set "$$%%random%%=%%a"
(for /f "tokens=1,* delims==" %%a in ('set $$') do echo(%%b)>newmaclist.txt
endlocal

还有一个限制:字面上的“%”符号会丢失...不过这是个好方法!也许您会对我的答案感兴趣,它还解决了潜在重复的“random”数字问题... - aschipfl
当执行回显语句时,回显必须关闭,因此@echo(%%b)是必要的。 - hunterhogan

2
我非常喜欢foxidrive方法。尽管如此,我想提供一个解决方案,消除所有列出的限制(尽管与cmd相关的限制,例如文件大小小于2 GiB和行长度小于约8 KiB仍然存在)。
关键是延迟扩展,需要切换以不丢失感叹号。这解决了所有特殊字符(如^&%!()<>|")的潜在问题。
计数器index已经实现,以便不会失去原始文本文件的任何一行,如果没有它,可能会发生这种情况,因为random可能返回重复值;附加了index后,生成的变量名$$!random!.!index!是唯一的。

命令findstr /N /R "^"会在原文件的每一行前加上一个行号和冒号。因此,对于for /F循环来说,没有任何一行是空白的,它也不会忽略这种情况。行号还隐含地解决了前导分号的问题,即for /F默认的eol字符。

最后,在输出之前,从每一行中删除第一个冒号(请记住,这是由于findstr添加的前缀),因此不再丢弃前导等号符。

所以这里是代码:

@echo off
setlocal EnableExtensions DisableDelayedExpansion

set /A "index=0"
for /f "delims=" %%a in ('findstr /N /R "^" "%~dpn0.lst"') do (
    setlocal EnableDelayedExpansion
    for /F %%b in ("$$!random!.!index!") do (
        endlocal
        set "%%b=%%a"
    )
    set /A "index+=1"
)
> "%~dpn0.new" (
    for /f "delims=" %%a in ('set $$') do (
        set "item=%%a"
        setlocal EnableDelayedExpansion
        echo(!item:*:=!
        endlocal
    )
)

endlocal
exit /B

做得好!我怎样可以一次使用多个文件?我在第一个“for”中添加了一个新文件并复制了第二个“for”,但是它没有正常工作。 - Ionut Bejinariu
谢谢,@IonutBejinariu!最简单的方法是将代码包装到一个for循环中:1.在脚本中用%%~F替换%~dpn0.lst%%~nF.new替换%~dpn0.new;2.在第一个setlocal命令行后插入:for %%F in ("file1.lst" "file2.lst" "files*.lst") do (;3.在最后一个endlocal命令之前插入:)... - aschipfl
谢谢,我会尝试的...希望我能成功...我是个新手。 :) - Ionut Bejinariu
我按照你说的做了,但是没有起作用。file.new 没有与原始文件合并,仍然留在文件夹中,而且脚本混淆了所有文件之间的行,这是一个大问题。 - Ionut Bejinariu
也可以在文件之间连接行,第四个文件中有26行而不是5行。第一个文件翻倍,第二个文件三倍,第三个文件的行数是原始行数的4倍。 - Ionut Bejinariu
显示剩余2条评论

2

将其放置在cmd文件中

for /f "tokens=2 delims=/" %%m in ('cmd /e:on /v:on /c "for /f %%f in (maclist.txt) do @echo !random!/%%f" ^| sort') do echo %%m

它生成一个 cmd,该 cmd 在内部 for 中读取 mac 列表,给 mac 加上随机值和斜杠前缀并对列表进行排序。然后,在外部 for 中使用斜杠作为分隔符将此列表拆分并打印 mac 地址。

1
这似乎是有效的。将文件名作为命令行参数传入即可随机化文件。
    @echo off
    setlocal EnableDelayedExpansion

    rem read the number of lines in the file
    rem the find prepends the line number so we catch blank lines
    for /f "delims=" %%n in ('find /c /v "" %1') do set "len=%%n"
    set len=!len:*: =!
    rem echo %1 has %len% lines

    rem Relocate as many lines as there are lines in the file
    for /l %%j in (1 1 !len!) do (
      rem echo starting round %%j

      rem geta random number between 1 and the number of lines in the file
      set /a var=!random! %% !len! + 1
      rem echo relocating line !var!

      rem make sure there is no temp file
      if exist %1.temp del %1.temp

      rem read each line of the file, write any that don't match and then write the one that does
      <%1 (
        for /l %%i in (1 1 !len!) do (

          rem if it is the target line then save it
          if %%i == !var! (
            set /p found=
            rem echo saving !found!
          )

          rem if it is the target line then write it
          if not %%i == !var! (
            set /p other=
            rem echo writing !other!
            echo !other!>> %1.temp
          )
        )
        rem now write the target line at the end
        rem echo appending !found!
        echo !found!>> %1.temp
      )

      rem replace the original with the temp version
      move %1.temp %1>nul
    )

    rem print the result
    type %1

我的比shuffle.bat复杂得多 - 为什么我没想到那样做呢??? - Jerry Jeremiah

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接