找回密码
 注册
搜索
[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
查看: 38937|回复: 19

[其他] 将 setlocal 和 endlocal 之间的变量 传递到 endlocal 之后,变量的数量不定

[复制链接]
发表于 2024-8-23 01:57:39 | 显示全部楼层 |阅读模式
将 setlocal 和 endlocal 之间的变量 传递到 endlocal 之后
如果,变量的名字确定,比较好办。
但是如果变量的数量不定,变量名不定,不通过临时文件,还有什么办法?
谢谢
发表于 2024-8-23 02:55:37 | 显示全部楼层
这样子么,不过得先弄成统一前缀格式的变量名,
可能不支持某些特殊字符,还有当前代码页不支持的字符会变成问号

for /f "tokens=1* delims==" %%a in ('set 变量名') do (
if "!aaa!" == "%aaa%" endlocal
set "%%a=%%b"
)

评分

参与人数 2技术 +2 收起 理由
newswan + 1 谢谢
buyiyang + 1 感谢分享

查看全部评分

发表于 2024-8-23 08:54:35 | 显示全部楼层
回复 1# newswan
我想在endlocal前,使用call命令跳转到变量延迟开关外面,暂不执行endlocal,使用完变量后再关闭变量延迟开关,应当可行。
发表于 2024-8-23 10:06:50 | 显示全部楼层

有关 !var! 续命给 %var% 是批处的一个经典话题,其中有一个 ‘坑’ 就是不能在复合语块(例如 for 或 if 括号内部)中完成,原因是cmd预处理要对复合语块中的所有 %var% 预赋值...
发表于 2024-8-23 10:27:20 | 显示全部楼层
本帖最后由 qixiaobin0715 于 2024-8-23 10:32 编辑

个人不喜欢call、goto这样的跳转命令,所以也不是太懂,大概就是这样子:
  1. @echo off
  2. for /l %%i in (1,1,3) do (
  3.     set str=%%i
  4.     setlocal enabledelayedexpansion
  5.     set str=0!str!
  6.     call :o
  7.     endlocal
  8. )
  9. echo,####%str%
  10. pause
  11. :o
  12. echo,%str%
复制代码
发表于 2024-8-23 12:38:33 | 显示全部楼层
  1. @echo off
  2. setlocal enabledelayedexpansion
  3. for /f "useback delims=" %%a in ("%~f0") do (
  4.         set /a _n+=1
  5.         set _!_n!=%%a
  6. )
  7. for /f "delims=" %%a in ('set _') do (
  8.         if not defined _end (
  9.                 endlocal
  10.                 set _end=1
  11.         )
  12.         set %%a
  13. )
  14. set _end=
  15. set _
  16. pause
复制代码
发表于 2024-8-23 14:03:46 | 显示全部楼层
本帖最后由 aloha20200628 于 2024-8-23 14:38 编辑


运行以下代码可见》4种实况说明 ‘延迟变量’ 开启前后的值变及其 ‘续命’ 的一个有效方法...

  1. @echo off &setlocal
  2. echo,第一轮
  3. set/a "v1=1,v2=2,v3=3"
  4. echo,        未开延迟变量》v1=%v1%,v2=%v2%,v3=%v3%
  5. setlocal enabledelayedexpansion
  6. set "v1=11" &set "v2=12" &set "v3=13"
  7. echo,        开启延迟变量》v1=%v1%,v2=%v2%,v3=%v3%
  8. endlocal
  9. echo,        关闭延迟变量》v1=%v1%,v2=%v2%,v3=%v3%
  10. echo,第二轮(续命之道)
  11. set/a "v1=1,v2=2,v3=3"
  12. echo,        未开延迟变量》v1=%v1%,v2=%v2%,v3=%v3%
  13. setlocal enabledelayedexpansion
  14. set "v1=21" &set "v2=22" &set "v3=23"
  15. echo,        开启延迟变量》v1=%v1%,v2=%v2%,v3=%v3%
  16. endlocal & set "v1=%v1%" &set "v2=%v2%" &set "v3=%v3%"
  17. echo,        关闭延迟变量》v1=%v1%,v2=%v2%,v3=%v3%
  18. echo,第三轮(复合语块-if)
  19. set/a "v1=1,v2=2,v3=3"
  20. echo,        未开延迟变量》v1=%v1%,v2=%v2%,v3=%v3%
  21. if 1 equ 1 (
  22.         setlocal enabledelayedexpansion
  23.         set "v1=31" &set "v2=32" &set "v3=33"
  24.         echo,        开启延迟变量》v1=%v1%,v2=%v2%,v3=%v3%
  25.         endlocal & set "v1=%v1%" &set "v2=%v2%" &set "v3=%v3%"
  26. )
  27. echo,        关闭延迟变量》v1=%v1%,v2=%v2%,v3=%v3%
  28. echo,第四轮(复合语块-for)
  29. set/a "v1=1,v2=2,v3=3"
  30. echo,        未开延迟变量》v1=%v1%,v2=%v2%,v3=%v3%
  31. for /l %%n in (1,1,1) do (
  32.         setlocal enabledelayedexpansion
  33.         set "v1=41" &set "v2=42" &set "v3=43"
  34.         echo,        开启延迟变量》v1=%v1%,v2=%v2%,v3=%v3%
  35.         endlocal & set "v1=%v1%" &set "v2=%v2%" &set "v3=%v3%"
  36. )
  37. echo,        关闭延迟变量》v1=%v1%,v2=%v2%,v3=%v3%
  38. endlocal&pause&exit/b
复制代码

评分

参与人数 2技术 +2 收起 理由
newswan + 1
qixiaobin0715 + 1 透彻!!!

查看全部评分

发表于 2024-8-23 14:59:02 | 显示全部楼层
回复 7# aloha20200628
第2轮好牌!!!
前不久我也遇到过这种情况,都是使用临时文件中转的,好麻烦。这个有用!简洁!
发表于 2024-8-23 15:16:11 | 显示全部楼层
本帖最后由 qixiaobin0715 于 2024-8-23 15:46 编辑

要注意,5楼代码跳转后,执行标签后面的代码时,变量延迟开关并没有关闭,返回时才关闭,每个完整循环完成关闭一次,特殊情况时有用。
发表于 2024-8-23 15:58:11 | 显示全部楼层
本帖最后由 77七 于 2024-8-23 16:00 编辑

成也预处理,败也预处理,老手在利用预处理;新手败给预处理
  1. setlocal
  2. set n=1
  3. endlocal & echo %n%
复制代码

  1. set n=1& echo %n%
复制代码



变量延迟扩展表示不服,爱用哪个就用哪个;关闭,只能用预处理

  1. set n=1& setlocal enabledelayedexpansion &echo %%n%%=[%n%](预处理=空值)  ^^!n^^!=[!n!](变量延迟扩展值)&endlocal & echo set "n=%n%"
复制代码
发表于 2024-8-23 17:05:32 | 显示全部楼层
不能把endlocal这道箍摘掉吗
发表于 2024-8-23 19:15:44 | 显示全部楼层
不临时存储上一个环境的变量的话,应该是没有办法了。
正如你所言,如果变量的名称确定比较好办,可以利用预处理针对性复制变量;但是如果变量的数量不定名称不定,意味着要完整复制变量环境,而这明显违背了使用 endlocal 的初心:
既要用 endlocal 结束本地化变量环境,然后又要该环境的所有变量,不就相当于没用 endlocal 吗?好奇你的应用场景是什么,如楼上所言何不摘掉 endlocal 呢?
发表于 2024-8-24 06:59:03 | 显示全部楼层
本帖最后由 HOPE2021 于 2024-8-24 07:25 编辑

回复 12# buyiyang
如果使用变量构造命令的话,应该可以,不过这对兼容性有很大压力(不同版本的 Windows 变量内容长度限制不同),所以不可能一次性复制大量变量,也难以复制特殊字符。

既要用 endlocal 结束本地化变量环境,然后又要该环境的所有变量,不就相当于没用 endlocal 吗?好奇你的应用场景是什么,如楼上所言何不摘掉 endlocal 呢?

其实不是,有些复杂运算可能需要启用延缓环境变量,但是程序的主体不需要,所以才有这种看似“奇怪”的需求。

以下命令在 Windows 2000(版本 5.00.2195)和 Windows 11(Microsoft Windows [版本 10.0.22631.4037])测试通过,简单地实现了这种需求,仅作抛砖引玉。
  1. @echo off
  2. SetLocal EnableDelayedExpansion
  3. set /a var1=1,var2=2,var3=3
  4. echo.已启用延缓环境变量
  5. echo.var1 = !var1!, var2 = !var2!, var3 = !var3!

  6. %================================================================%
  7. %= 设定要复制的变量名列表 =%
  8. set "__varlist=var1 var2 var3"
  9. set "__command="

  10. for %%_ in (!__varlist!) do (
  11.     set "__command=!__command! "%%_=%%%%_%%""
  12. )

  13. for /f "delims=" %%_ in ('echo.!__command!') do (
  14.     echo.{%%_}
  15.     endlocal
  16.     for %%` in (%%_) do (
  17.         set %%`
  18.     )
  19. )
  20. %================================================================%

  21. set __varlist
  22. set __command

  23. echo.已禁用延缓环境变量
  24. echo.var1 = %var1%, var2 = %var2%, var3 = %var3%
  25. %= 下面一行没有任何意义,只是想说明已禁用延缓环境变量 =%
  26. echo.var1 = !var1!, var2 = !var2!, var3 = !var3!

  27. pause
复制代码

评分

参与人数 2技术 +2 收起 理由
newswan + 1 谢谢
buyiyang + 1 感谢分享

查看全部评分

发表于 2024-8-24 08:58:10 | 显示全部楼层
回复 13# HOPE2021

我以为楼主只用SetLocal,用SetLocal EnableDelayedExpansion的话因为处理特殊字符!和^麻烦确实有时候需要关闭,要是批处理能使用变量延迟又不变量局域化就好了。
如果要复制的变量名称和数量不确定的话,应该需要像2楼那样用set列出所有变量列表。
 楼主| 发表于 2024-8-25 03:47:54 | 显示全部楼层
回复 6# 77七

这个思路用过。在 setlocal 的时候
  1. set _inlocal_=True
复制代码
您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|手机版|小黑屋|批处理之家 ( 渝ICP备10000708号 )

GMT+8, 2026-3-17 21:05 , Processed in 0.018728 second(s), 9 queries , File On.

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表