V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
qazwsxkevin
V2EX  ›  程序员

有非常熟悉 WIN Cmd 批处理的高手吗? for 循环每次赋予环境变量,会有问题

  •  
  •   qazwsxkevin · 2023-01-26 14:50:22 +08:00 · 1335 次点击
    这是一个创建于 666 天前的主题,其中的信息可能已经有所发展或是发生改变。
    set Clicount=32
    
    @REM do creat client file
    for /l %%a in (2,1,%Clicount%) do (
    
    @REM get rand ASCII code.
    @REM 每个循环需要一个不同的随机字符串,并把随机字符串赋到%RANDSTR%,给其它程序使用,自撸了 python 生成随机数+pyinstaller ,打包成成 rand.exe,放在.\bin 下面
    @REM 下面我按网上能找到的两种做法,CMD 环境或程序输出,获取输出内容到%RANDSTR%
    
    @REM 做法一:
    .\bin\randstr.exe -l8 -d8>.\tmp\randstr.txt
    set /p RANDSTR=<.\tmp\randstr.txt
    del /q .\tmp\randstr.txt
    @REM 方法一,在第一个循环周期内,%RANDSTR%会被正确赋值,被其它程序正确使用,
    @REM 在第二个循环周期开始,会变成空值
    
    @REM 做法二:
    @FOR /F %%i IN ('.\bin\randstr.exe -l8 -d8') DO @set RANDSTR=%%i
    @REM 方法二:在第一个循环周期内,%RANDSTR%可以正确被赋值
    @REM 在第二个循环周期开始,%RANDSTR%不会变化,往后的循环周期,%RANDSTR%都是第一次的值
    @REM 猜测是,批处理环境不能在 FOR 里面嵌套 FOR ?
    
    @REM 怎么办? 或者有没有其他变通的方式,使得 for /l %%a in (2,1,%Clicount%)这个循环里,可以正常%RANDSTR%赋值?
    
    @.\bin\rar a -hp%rarpasswd% -k -ep1 -m5 %clientdir%\RARpacket\x86\x86_%%a_%RANDSTR%.rar C:\xxxxx\xxxxx\x86\.
    
    @REM End of do creat client files packet.
    )
    
    #自己随手写的随机字符串,没讲究,能用就可以了
    import sys
    import random
    import string
    
    
    helpStr = """
    command: randStr -option len
    option:
           -l  Letter,'Aa-Zz'
           -d  Number,'0-9'
           -c  Chars,'@$#_%?'
    """
    
    letters = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz'
    numbers = '0123456789'
    chars = '@$#_%?'
    
    if __name__ == '__main__':
    
        if len(sys.argv) == 1:
            print('Options error...')
            print(helpStr)
            sys.exit()
    
        optionStr = (((''.join(sys.argv[1:])).replace(' ','')).replace('-','')).strip()
    
        rChar = ''
    
        if len(optionStr) >= 2:
            optionList = []
            tmpStr = ''
            if optionStr[0].isalpha():
                tmpStr = ''.join(optionStr[0])
                for c in optionStr[1:]:
                    if c.isdigit():
                        tmpStr = tmpStr + c
                    if c.isalpha():
                        optionList.append(tmpStr)
                        tmpStr = c
                else:
                    optionList.append(tmpStr)
    
            set_optionList = list(set(optionList))
    
            for i in set_optionList:
                if i[0] == 'l':
                    for c in range(int(i[1:])):
                        randNum = random.randint(0, len(letters))
                        rChar += letters[randNum - 1]
    
                if i[0] == 'd':
                    for c in range(int(i[1:])):
                        randNum = random.randint(0, len(numbers))
                        rChar += numbers[randNum - 1]
    
                if i[0] == 'c':
                    for c in range(int(i[1:])):
                        randNum = random.randint(0, len(chars))
                        rChar += chars[randNum - 1]
    
            if rChar:
                rCharList = list(rChar)
                random.shuffle(rCharList)
                print(''.join(rCharList))
        else:
            print('Options error...')
            print(helpStr)
            sys.exit()
    
    5 条回复    2023-01-26 22:13:04 +08:00
    geelaw
        1
    geelaw  
       2023-01-26 14:53:14 +08:00 via iPhone   ❤️ 1
    piku
        2
    piku  
       2023-01-26 20:42:46 +08:00
    FOR /F %%i IN ('.\bin\randstr.exe -l8 -d8') DO ----这个括号内的值只会在循环开始时读取一次,可以考虑先生成若干行随机结果,每次去其中取一行?
    piku
        3
    piku  
       2023-01-26 20:56:23 +08:00
    set /p RANDSTR=<.\tmp\randstr.txt ----可能问题在于,管道操作(<)在批处理中分为 stdout ,stdin ,stderr ,无法从正确的流中取得值
    piku
        4
    piku  
       2023-01-26 21:06:34 +08:00   ❤️ 1
    好了第一种知道是怎么回事了。bat 在运行时,是先将其中所有变量解析出来然后再运行的。每次循环可以正确设置变量值,但在循环内引用环境变量时只会保存第一次的值。所以调用随机数变量的行为不能在循环内。

    既然用 python 写了,为啥不直接用 python 处理环境变量问题
    hxy100
        5
    hxy100  
       2023-01-26 22:13:04 +08:00   ❤️ 1
    直接在循环体内调用迭代变量不行吗?为什么需要赋值?
    ----
    @echo off
    set Clicount=32

    @REM do creat client file
    for /l %%a in (2,1,%Clicount%) do (

    @FOR /F %%i IN ('.\bin\randstr.exe -l8 -d8') DO (
    @.\bin\rar a -hp%rarpasswd% -k -ep1 -m5 %clientdir%\RARpacket\x86\x86_%%a_%%i.rar C:\xxxxx\xxxxx\x86\.
    )

    REM ENDLOCAL
    @REM End of do creat client files packet.
    )

    ----
    另:如果需要在循环体内进行赋值操作, 可以考虑使用 setlocal enabledelayedexpansion 指令
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2775 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 13:52 · PVG 21:52 · LAX 05:52 · JFK 08:52
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.