标题: [其他] 将 setlocal 和 endlocal 之间的变量 传递到 endlocal 之后,变量的数量不定 [打印本页]
作者: newswan 时间: 2024-8-23 01:57 标题: 将 setlocal 和 endlocal 之间的变量 传递到 endlocal 之后,变量的数量不定
将 setlocal 和 endlocal 之间的变量 传递到 endlocal 之后
如果,变量的名字确定,比较好办。
但是如果变量的数量不定,变量名不定,不通过临时文件,还有什么办法?
谢谢
作者: Five66 时间: 2024-8-23 02:55
这样子么,不过得先弄成统一前缀格式的变量名,
可能不支持某些特殊字符,还有当前代码页不支持的字符会变成问号
for /f "tokens=1* delims==" %%a in ('set 变量名') do (
if "!aaa!" == "%aaa%" endlocal
set "%%a=%%b"
)
作者: qixiaobin0715 时间: 2024-8-23 08:54
回复 1# newswan
我想在endlocal前,使用call命令跳转到变量延迟开关外面,暂不执行endlocal,使用完变量后再关闭变量延迟开关,应当可行。
作者: aloha20200628 时间: 2024-8-23 10:06
有关 !var! 续命给 %var% 是批处的一个经典话题,其中有一个 ‘坑’ 就是不能在复合语块(例如 for 或 if 括号内部)中完成,原因是cmd预处理要对复合语块中的所有 %var% 预赋值...
作者: qixiaobin0715 时间: 2024-8-23 10:27
本帖最后由 qixiaobin0715 于 2024-8-23 10:32 编辑
个人不喜欢call、goto这样的跳转命令,所以也不是太懂,大概就是这样子:- @echo off
- for /l %%i in (1,1,3) do (
- set str=%%i
- setlocal enabledelayedexpansion
- set str=0!str!
- call :o
- endlocal
- )
- echo,####%str%
- pause
- :o
- echo,%str%
复制代码
作者: 77七 时间: 2024-8-23 12:38
- @echo off
- setlocal enabledelayedexpansion
- for /f "useback delims=" %%a in ("%~f0") do (
- set /a _n+=1
- set _!_n!=%%a
- )
- for /f "delims=" %%a in ('set _') do (
- if not defined _end (
- endlocal
- set _end=1
- )
- set %%a
- )
- set _end=
- set _
- pause
复制代码
作者: aloha20200628 时间: 2024-8-23 14:03
本帖最后由 aloha20200628 于 2024-8-23 14:38 编辑
运行以下代码可见》4种实况说明 ‘延迟变量’ 开启前后的值变及其 ‘续命’ 的一个有效方法...- @echo off &setlocal
- echo,第一轮
- set/a "v1=1,v2=2,v3=3"
- echo, 未开延迟变量》v1=%v1%,v2=%v2%,v3=%v3%
- setlocal enabledelayedexpansion
- set "v1=11" &set "v2=12" &set "v3=13"
- echo, 开启延迟变量》v1=%v1%,v2=%v2%,v3=%v3%
- endlocal
- echo, 关闭延迟变量》v1=%v1%,v2=%v2%,v3=%v3%
- echo,第二轮(续命之道)
- set/a "v1=1,v2=2,v3=3"
- echo, 未开延迟变量》v1=%v1%,v2=%v2%,v3=%v3%
- setlocal enabledelayedexpansion
- set "v1=21" &set "v2=22" &set "v3=23"
- echo, 开启延迟变量》v1=%v1%,v2=%v2%,v3=%v3%
- endlocal & set "v1=%v1%" &set "v2=%v2%" &set "v3=%v3%"
- echo, 关闭延迟变量》v1=%v1%,v2=%v2%,v3=%v3%
- echo,第三轮(复合语块-if)
- set/a "v1=1,v2=2,v3=3"
- echo, 未开延迟变量》v1=%v1%,v2=%v2%,v3=%v3%
- if 1 equ 1 (
- setlocal enabledelayedexpansion
- set "v1=31" &set "v2=32" &set "v3=33"
- echo, 开启延迟变量》v1=%v1%,v2=%v2%,v3=%v3%
- endlocal & set "v1=%v1%" &set "v2=%v2%" &set "v3=%v3%"
- )
- echo, 关闭延迟变量》v1=%v1%,v2=%v2%,v3=%v3%
- echo,第四轮(复合语块-for)
- set/a "v1=1,v2=2,v3=3"
- echo, 未开延迟变量》v1=%v1%,v2=%v2%,v3=%v3%
- for /l %%n in (1,1,1) do (
- setlocal enabledelayedexpansion
- set "v1=41" &set "v2=42" &set "v3=43"
- echo, 开启延迟变量》v1=%v1%,v2=%v2%,v3=%v3%
- endlocal & set "v1=%v1%" &set "v2=%v2%" &set "v3=%v3%"
- )
- echo, 关闭延迟变量》v1=%v1%,v2=%v2%,v3=%v3%
- endlocal&pause&exit/b
复制代码
作者: qixiaobin0715 时间: 2024-8-23 14:59
回复 7# aloha20200628
第2轮好牌!!!
前不久我也遇到过这种情况,都是使用临时文件中转的,好麻烦。这个有用!简洁!
作者: qixiaobin0715 时间: 2024-8-23 15:16
本帖最后由 qixiaobin0715 于 2024-8-23 15:46 编辑
要注意,5楼代码跳转后,执行标签后面的代码时,变量延迟开关并没有关闭,返回时才关闭,每个完整循环完成关闭一次,特殊情况时有用。
作者: 77七 时间: 2024-8-23 15:58
本帖最后由 77七 于 2024-8-23 16:00 编辑
成也预处理,败也预处理,老手在利用预处理;新手败给预处理- setlocal
- set n=1
- endlocal & echo %n%
复制代码
复制代码
变量延迟扩展表示不服,爱用哪个就用哪个;关闭,只能用预处理
- set n=1& setlocal enabledelayedexpansion &echo %%n%%=[%n%](预处理=空值) ^^!n^^!=[!n!](变量延迟扩展值)&endlocal & echo set "n=%n%"
复制代码
作者: idwma 时间: 2024-8-23 17:05
不能把endlocal这道箍摘掉吗
作者: buyiyang 时间: 2024-8-23 19:15
不临时存储上一个环境的变量的话,应该是没有办法了。
正如你所言,如果变量的名称确定比较好办,可以利用预处理针对性复制变量;但是如果变量的数量不定名称不定,意味着要完整复制变量环境,而这明显违背了使用 endlocal 的初心:
既要用 endlocal 结束本地化变量环境,然后又要该环境的所有变量,不就相当于没用 endlocal 吗?好奇你的应用场景是什么,如楼上所言何不摘掉 endlocal 呢?
作者: HOPE2021 时间: 2024-8-24 06:59
本帖最后由 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])测试通过,简单地实现了这种需求,仅作抛砖引玉。- @echo off
- SetLocal EnableDelayedExpansion
- set /a var1=1,var2=2,var3=3
- echo.已启用延缓环境变量
- echo.var1 = !var1!, var2 = !var2!, var3 = !var3!
-
- %================================================================%
- %= 设定要复制的变量名列表 =%
- set "__varlist=var1 var2 var3"
- set "__command="
-
- for %%_ in (!__varlist!) do (
- set "__command=!__command! "%%_=%%%%_%%""
- )
-
- for /f "delims=" %%_ in ('echo.!__command!') do (
- echo.{%%_}
- endlocal
- for %%` in (%%_) do (
- set %%`
- )
- )
- %================================================================%
-
- set __varlist
- set __command
-
- echo.已禁用延缓环境变量
- echo.var1 = %var1%, var2 = %var2%, var3 = %var3%
- %= 下面一行没有任何意义,只是想说明已禁用延缓环境变量 =%
- echo.var1 = !var1!, var2 = !var2!, var3 = !var3!
-
- pause
复制代码
作者: buyiyang 时间: 2024-8-24 08:58
回复 13# HOPE2021
我以为楼主只用SetLocal,用SetLocal EnableDelayedExpansion的话因为处理特殊字符!和^麻烦确实有时候需要关闭,要是批处理能使用变量延迟又不变量局域化就好了。
如果要复制的变量名称和数量不确定的话,应该需要像2楼那样用set列出所有变量列表。
作者: newswan 时间: 2024-8-25 03:47
回复 6# 77七
这个思路用过。在 setlocal 的时候复制代码
作者: newswan 时间: 2024-8-25 04:03
如果比较复杂的,setlocal 隔离还是必要的,虽然隔离要麻烦些。
我现在遇到的一个情况是,以前有一个脚本,单独使用的,现在要在另一个脚本里调用,两个脚本里有变量冲突。
认为,与其改变量名,不如 setlocal ,仅仅返回需要的变量,把输出的变量名,前面加一个前缀,_a_var1
用一个通用的办法比较好些。
作者: newswan 时间: 2024-8-25 04:05
本帖最后由 newswan 于 2024-8-25 04:10 编辑
回复 13# HOPE2021
变量名 变量值 不够多的时候,可以,一般的脚本不会有那么多输出。
可以用把参数的方式返回。调用的地方获取整个字符串后,再进行处理。
作者: newswan 时间: 2024-8-25 04:13
回复 3# qixiaobin0715
代码位置是在 endlocal 之外,但是逻辑上还是在 endlocal 运行之前
作者: newswan 时间: 2024-8-25 04:39
本帖最后由 newswan 于 2024-8-26 09:55 编辑
最后选择这种方式
a.bat- @echo off
- setlocal
-
- set _var1_=111
- call b.bat
-
- echo :1
- set _
-
- for /f "usebackq tokens=1,* delims==" %%a in (`set __`) do (
- set _b%%a=%%b
- set %%a=
- )
-
- echo :2
- set _
-
- endlocal
-
- pause
- exit/b
复制代码
b.bat- @echo off
- setlocal enableDelayedExpansion
-
- set __var1__=value1
- set __var2__=value2
- set __var3__=value3
-
- for /f "delims=" %%a in ('set __') do (
- if defined _inLocal_ (endlocal)
- set %%a
- )
-
- exit/b
复制代码
个人习惯,变量用 "_" 开头,要输出的变量,用 "__" 开头
作者: aloha20200628 时间: 2024-8-25 10:49
本帖最后由 aloha20200628 于 2024-8-25 10:56 编辑
回复 1# newswan
主批通过 call 调用子批,其实是共享主批的变量环境,除非子批用 setlocal [...] 独建自己的本地变量环境,但子批最后将本地变量 ‘续命’ 给主批,还是要避免与主批的同类同名变量的覆盖问题,因此,多个子批被主批通过 call 调用的一个简捷而稳妥之策,是由主批给每个子批分配共享变量名区段(子批独建的本地变量除外)用前缀或后缀或流水号标识等方法,不必再绕经每个子批的 ‘续命’
弯道,此法不仅是针对批处,其他脚本依然... 仅供参考
欢迎光临 批处理之家 (http://bathome.net./) |
Powered by Discuz! 7.2 |