Board logo

标题: [已结]寻willsort !!,DOS能不能嵌套多层变量? [打印本页]

作者: GOTOmsdos     时间: 2005-4-27 00:00    标题: [已结]寻willsort !!,DOS能不能嵌套多层变量?

最近做东东,发现DOS好象不能嵌套多层变量,加了COMMAND /C 也没大用,顶多多显示一层
比如,  有%VAR%=10,把VAR赋给%1,,,,  就不能用%%1%来取到10,
同理,SET VAR2=VAR, %%VAR%%也不能取到10,
也就是说,如果想用另一个变量同时取到某个变量名本身及其值! 这样就不方便了,
比如,我上边的修改游戏成绩:
有很多对值,一对值就是两个项目(用变量描述,比如T1表示第一号赛道,%T1%表示通过的次数),加起来就是60变量!
但通过一个%1解决不了.如下:
把T1 T2 T3...用SHIFT赋给%1, 用%%1%取到值,但不能嵌套
用FOR %%A IN (1 2 3 ....) DO CALL XXX T%%A %T%%A% 也不能嵌套
所以,害的我要列出60个变量!!
??

[ Last edited by HAT on 2008-11-3 at 20:36 ]
作者: chenhui530     时间: 2005-4-27 00:00


  Quote:
以下是引用GOTOmsdos在2005-4-27 0:01:56的发言:


最近做东东,发现DOS好象不能嵌套多层变量,加了COMMAND /C 也没大用,顶多多显示一层
比如,  有%VAR%=10,把VAR赋给%1,,,,  就不能用%%1%来取到10,
同理,SET VAR2=VAR, %%VAR%%也不能取到10,
也就是说,如果想用另一个变量同时取到某个变量名本身及其值! 这样就不方便了,
比如,我上边的修改游戏成绩:
有很多对值,一对值就是两个项目(用变量描述,比如T1表示第一号赛道,%T1%表示通过的次数),加起来就是60变量!
但通过一个%1解决不了.如下:
把T1 T2 T3...用SHIFT赋给%1, 用%%1%取到值,但不能嵌套
用FOR %%A IN (1 2 3 ....) DO CALL XXX T%%A %T%%A% 也不能嵌套
所以,害的我要列出60个变量!!
??

DOS在使用FOR语句的时候是不能进行多个变量循环的~
以前我也遇到这种情况
作者: GOTOmsdos     时间: 2005-4-27 00:00
好象FOR之外的其他情况也是这样的..
作者: willsort     时间: 2005-4-27 00:00
Re GOTOmsdos:
  这是个很有代表性的问题。
  变量不能递归引用,这源于变量标识符'%'的特性。它是一个转义字符,英文是Escape character,有人将它译为“脱字符”或者“逃逸字符”。这很形象,因为它每被命令解释器解释一次,就脱一层或者说逃逸一次,比如%%%%会变成%%,%%会变成%,%会直接消失并且转义后面的字符,这类似C语言中的'\'。所以在变量嵌套引用时,多个%叠加使用,会出现脱字符的现象,而并不会如你想象的那样工作。另外,即时'%'没有叠加,类似于这样,'%prename_%mainname%_sufname%',也只会将第二个'%'认作变量 'prename_' 的名字结束标志,而非 'mainname' 的开始标志,仍然无法实现你原定的意图。
  解决的方法很简单,现在比较忙,没有多少时间详细解释。现给你一个实例,相信不难看懂的,主要还是利用%的“逃逸”特性,只不过“逃逸”的顺序有所不同。

  Quote:
:: NestRef.bat - 变量嵌套引用实例
:: Will Sort - 2005/04/27 - CMD@WinXP
@echo off
if "%1"==":" goto %2
:Main
for %%e in (T1 T2 T3 T4 T5 T6) do set %%e=value_of_%%e
call %0 : Loop T1 T2 T3 T4 T5 T6
for %%e in (T1 T2 T3 T4 T5 T6) do set %%e=
if exist _NestRef.bat del _NestRef.bat

:Loop
if "%3"=="" goto end
echo set value=%%%3%%>_NestRef.bat
call _NestRef.bat
echo %3='%value%'
shift
goto loop
:end

[此贴子已经被作者于2005-4-27 16:06:42编辑过]



作者: GOTOmsdos     时间: 2005-4-27 00:00
有启发! 我刚才试了下,可以。%%1%是脱落了一层。不过好象%%ABC%%不会脱落啊。除了脱落关键是要先ECHO
作者: willsort     时间: 2005-4-28 00:00
Re GOTOmsdos:  “除了脱落关键是要先ECHO”  %%%3%% 在 echo 之前就被命令解释器转义了,其中前两个和后两个%“脱落”成一个%,%3被转义为实际的变量名,如果此时%3是T1,则 echo 一句就被转义成了:  echo set value=%T1%>_NestRef.bat  当然,这只是命令解释器的内部形式,在批处理中是看不到的,但是如果你把>_NestRef.bat和文头的@echo off去掉,就会在命令行中看到类似的形式“set value=%T1%”。  至于 %%ABC%% ,你改成 %%%ABC%%% 就好了。
作者: GOTOmsdos     时间: 2005-4-28 00:00
1  既然在 echo 之前就被命令解释器转义了,那么是不是不用ECHO也行?2   我试过几次了,%%ABC%% 没有脱落呀..如下:set ab=qweset abc=abecho md %%abc%%>test.battest运行后,就执行了md qwe(%abc%是ab, %%abc%%就是qwe.没有脱落呀)
作者: GOTOmsdos     时间: 2005-4-28 00:00
发现,%%ABC%%确实不行,%%%ABC%%%才行...
作者: willsort     时间: 2005-4-28 00:00
Re GOTOmsdos:  1  既然在 echo 之前就被命令解释器转义了,那么是不是不用ECHO也行?  变量串的转义只有命令解释器能实现,也就是在它读取Bat中的命令行时;你可以尝试不改 echo 那句,然后直接注释掉 @echo off,然后你可以在命令行观察到 echo 一句的原形了。  但是,这并不是意味着可以轻易舍弃 echo ,因为我们的程序实际上是进行了二次转义,第一次将 '%%%3%% '转成了 %T1% (或者其他变量名),第二次则将 %T1% 转成了 value_of_T1。要实现二次转义,必须让命令解释器读取二次Bat(或者命令行也有可能),而要两次读取,就必须产生中间的临时bat,此时 echo 是最佳也最简单的选择。
作者: GOTOmsdos     时间: 2005-4-29 00:00    标题: 终于成功地运用了DOS的变量嵌套!从而解决了通过"递减和递增

这个ECHO还真是关键呢..
终于成功地运用了DOS的变量嵌套!从而解决了通过"递减和递增"简化了WBAT的简易DOS浏览器!!!
"递减和递增"简化是最简化的...(写出来的变量只用了区区三个!,小小WBAT和GET就实现了浏览几乎无限制的深层目录及其文件!,也可顺带编辑文本文件,执行可执行程序,批处理程序,也可随时把用户的目录赋给一个变量....麻雀虽小,五脏具全..并且支持带间隔的长名目录和中文!) 共大家参考,尤其是学习WBAT和GET的...相信会有很大帮助的!..
很满意! 再次感谢WILLSORT!
简化了的WBAT如下DOS71下测试成功!) 要求: 加载DOSLFN,正确加载TW
@echo off
goto begin
:dirbars "上一级—→"[x]
[退  出]
[预  选]
[看文件]
[看目录]
:
:filebars "   上一级—→"[x]
[退  出]
[运行批处理文件]
[运行可执行文件]
[编辑文本文件]
[查看文件信息]
:
:begin
if exist drive.txt copy drive.txt dir0.txt>nul
if exist dir0.txt goto 0dir
wbat cls ! box "没有驱动器!" 退出
goto end
:0dir
set get=0
:dir0
call w.bat list dir%get%.txt
if errorlevel 100 goto end
:putdisk
if not exist notready.txt goto dirbar1
find /i "%wbat%" notready.txt>nul
if errorlevel 1 goto dirbar1
wbat box "您还没有在%wbat%盘放入盘片!" 重试
call diskfind
goto putdisk
:dirbar1
set get=1
set dir%get%=%wbat%
:dirbars1
wbat box @%0:dirbars
if errorlevel 100 goto dirbsub1
if errorlevel 4 goto dir1
if errorlevel 3 goto flist1
if errorlevel 2 goto pikdir1
goto end
:dir1
if %get%==0 goto dir0
if %get%==1 goto rootdir
echo @echo off>nestvar.bat
echo dir "%%dir%get%%%" /b/ad/one>>nestvar.bat
command /c call nestvar>dir%get%.txt
goto subdir
:rootdir
dir %dir1%\ /b/ad/one>dir1.txt
:subdir
get f dir%get%.txt /vfsize>nul
if not "%fsize%"=="0" goto dir1y
wbat box "没有子目录!" 上一级,退出
if errorlevel 2 goto end
goto dirbars1
:dir1y
call w.bat list dir%get%.txt
if errorlevel 100 goto dirbars1
get r "+" %get% /w1 /vgetadd1>nul
echo set dir%getadd1%=%%dir%get%%%\%wbat%>nestvar.bat
call nestvar
wbat box @%0:dirbars
if errorlevel 100 goto dir1y
if errorlevel 4 goto dir2
if errorlevel 3 goto flist2
if errorlevel 2 goto pikdir2
goto end
:flist1
if %get%==1 goto rootfile
echo @echo off>nestvar.bat
echo dir "%%dir%get%%%" /b/a-d/one>>nestvar.bat
command /c call nestvar>flist%get%.txt
goto subfile
:rootfile
dir %dir1%\ /b/a-d/one>flist1.txt
:subfile
get f flist%get%.txt /vfsize>nul
if not "%fsize%"=="0" goto flist1y
wbat box "没有文件!" 上一级,退出
if errorlevel 2 goto end
goto dirbars1
:flist1y
call w.bat list flist%get%.txt
if errorlevel 100 goto dirbars1
:fbars1
wbat box @%0:filebars
if errorlevel 100 goto flist1y
if errorlevel 5 goto info1
if errorlevel 4 goto text1
if errorlevel 3 goto exec1
if errorlevel 2 goto bat1
goto end
:info1
echo @echo off>nestvar.bat
echo dir "%%dir%get%%%\%wbat%" /a>>nestvar.bat
command /c call nestvar>info1.txt
wbat list info1.txt
goto fbars1
:text1
echo @echo off>nestvar.bat
echo edit "%%dir%get%%%\%wbat%">>nestvar.bat
call nestvar
goto fbars1
:exec1
echo @echo off>nestvar.bat
echo "%%dir%get%%%\%wbat%">>nestvar.bat
call nestvar
goto fbars1
:bat1
echo @echo off>nestvar.bat
echo "%%dir%get%%%\%wbat%">>nestvar.bat
call nestvar
goto fbars1
:pikdir1
echo @echo off>nestvar.bat
echo set gamesave=%%dir%get%%%>>nestvar.bat
call nestvar
goto end
:dirbsub1
get r "-" %get% /w1>nul
goto dir1
:dir2
get r "+" %get% /w1>nul
goto dir1
:flist2
get r "+" %get% /w1>nul
goto flist1
:pikdir2
get r "+" %get% /w1>nul
goto pikdir1
:end

[此贴子已经被作者于2005-4-29 2:51:28编辑过]



作者: willsort     时间: 2005-4-29 00:00
Re GOTOmsdos:  我对Wbat没有研究,只是看了一下程序的大致框架,感觉还有精简的空间。  比如:info1,:text1,:exec1, :bat1等,还有 :dir2,:flist2,:pkdir2等都有许多重复性的代码。向 netvar.bat 中写入 @echo off  也是不必要的,因为被调用的批处理会继承调用者的 echo 状态。  另外,有一种模糊的感觉,就是你的程序模块分划似乎不太合理,造成了类似 :dir2 :flist2 等泛义标签的存在,也在一定程度上造成了重复代码的出现。希望你能做出更大的改进!
作者: GOTOmsdos     时间: 2005-4-29 00:00
:info1,:text1,:exec1, :bat1是多了两句一样的,但要改还是再加GOTO,也差不多,而且可读性就弱一点了.发现EXEC和BAT是一样的,这要精简一下
:dir2,:flist2,:pkdir2 各自两句,实际上就是一句 %GET%加1再各自去:dir1,:flist1,:pkdir1这是没法再减了..因为后面是GOTO,硬要改反而复杂化了..
子BAT中的@ECHO OFF.  是这样,当时测试时,可能是单独BAT测的 ,结果把DIR 目录,等等也弄到了文件中,所以就加上了
现在你一提醒,已经有主BAT了,就不再需要@ECHO OFF了
至于标签后的数字,当时没有精简时,数字就是表示目录层数的,现在不需要层数了,自然可以去掉的...
另,由于第一层是根目录,跟后面的子目录,执行过程是不一样的,所以没法精简掉..后面就是只用一层子目录的过程进行递增递减的...
小改一下再贴出来...

[此贴子已经被作者于2005-4-29 20:06:40编辑过]



作者: GOTOmsdos     时间: 2005-4-29 00:00
改好了
刚才在纯DOS下试了不在子BAT中加@ECHO OFF,但是,结果确实仍然输出了命令行本身,把它定向到了文件,这就不对了.
结果,还是加上去了,就没问题了..
改后如下:
@echo off
goto begin
:dirbars "上一级—→"[x]
[退  出]
[预  选]
[看文件]
[看目录]
:
:filebars "   上一级—→"[x]
[退  出]
[运行批处理文件]
[运行可执行文件]
[编辑文本文件]
[查看文件信息]
:
:begin
if exist drive.txt goto drive
wbat cls ! box "没有驱动器!" 退出
goto end
:drive
call w.bat list drive.txt
if errorlevel 100 goto end
:putdisk
if not exist notready.nst goto init1
find /i "%wbat%" notready.nst>nul
if errorlevel 1 goto init1
wbat box "您还没有在%wbat%盘放入盘片!" 重试
call diskfind
goto putdisk
:init1
set get=1
set dir%get%=%wbat%
:dirb
wbat box @%0:dirbars
if errorlevel 100 goto sub1
if errorlevel 4 goto dir
if errorlevel 3 goto file
if errorlevel 2 goto pick
goto end
:dir
if %get%==0 goto drive
if %get%==1 goto rootdir
echo @echo off>nestvar.bat
echo dir "%%dir%get%%%" /b/ad/one>>nestvar.bat
command /c call nestvar>put.nst
goto subdir
:rootdir
dir %dir1%\ /b/ad/one>put.nst
:subdir
get f put.nst /vfsize>nul
if not "%fsize%"=="0" goto havedir
wbat box "没有子目录!" 上一级,退出
if errorlevel 2 goto end
goto dirb
:havedir
call w.bat list put.nst
if errorlevel 100 goto dirb
get r "+" %get% /w1 /vgetadd1>nul
echo @echo off>nestvar.bat
echo set dir%getadd1%=%%dir%get%%%\%wbat%>>nestvar.bat
call nestvar
wbat box @%0:dirbars
if errorlevel 100 goto havedir
if errorlevel 4 goto diradd1
if errorlevel 3 goto fileadd1
if errorlevel 2 goto pickadd1
goto end
:file
if %get%==1 goto rootfile
echo @echo off>nestvar.bat
echo dir "%%dir%get%%%" /b/a-d/one>>nestvar.bat
command /c call nestvar>put.nst
goto subfile
:rootfile
dir %dir1%\ /b/a-d/one>put.nst
:subfile
get f put.nst /vfsize>nul
if not "%fsize%"=="0" goto havefile
wbat box "没有文件!" 上一级,退出
if errorlevel 2 goto end
goto dirb
:havefile
call w.bat list put.nst
if errorlevel 100 goto dirb
:fileb
wbat box @%0:filebars
if errorlevel 100 goto havefile
if errorlevel 5 goto info
if errorlevel 4 goto text
if errorlevel 3 goto exec-bat
if errorlevel 2 goto exec-bat
goto end
:info
echo @echo off>nestvar.bat
echo dir "%%dir%get%%%\%wbat%" /a>>nestvar.bat
command /c call nestvar>putfile.nst
wbat list putfile.nst
goto fileb
:text
echo @echo off>nestvar.bat
echo edit "%%dir%get%%%\%wbat%">>nestvar.bat
call nestvar
goto fileb
:exec-bat
echo @echo off>nestvar.bat
echo "%%dir%get%%%\%wbat%">>nestvar.bat
call nestvar
goto fileb
:pick
echo @echo off>nestvar.bat
echo set gamesave=%%dir%get%%%>>nestvar.bat
call nestvar
goto end
:sub1
get r "-" %get% /w1>nul
goto dir
:diradd1
get r "+" %get% /w1>nul
goto dir
:fileadd1
get r "+" %get% /w1>nul
goto file
:pickadd1
get r "+" %get% /w1>nul
goto pick
:end
for %%a in (nestvar.bat put.nst putfile.nst) do if exist %%a del %%a

[此贴子已经被作者于2005-4-29 20:14:58编辑过]



作者: willsort     时间: 2005-4-29 00:00
Re GOTOmsdos:  请告知你测试的纯DOS的版本,我在MS-DOS6.22和MS-DOS7.10中测试,未遇到此问题。
作者: GOTOmsdos     时间: 2005-4-29 00:00
就是在WENGIER的MSDOS7.10啊,而且几乎没加载什么TSR哦,更没用SHELL= 来改变COMMAND 很普通的环境.
作者: GOTOmsdos     时间: 2005-4-29 00:00
另,发现,command /c call nestvar>putfile.nst如果不用command /c 后面的重定向就不起作用了...
作者: willsort     时间: 2005-4-29 00:00
Re GOTOmsdos:  刚才有测试了以下,使用call时,使用的是当前command的外壳,而echo的状态在此外壳中全局有效。而使用command/c时,使用的是command生成的新外壳,echo状态被复位。  推测你使用command/c调用批处理,是想获取它的输出;其实,它在批处理内部就可以重定向到文件。当然,写入这个带有重定向符号的语句行需要一些技巧:
echo dir "%%dir%get%%%\%wbat%" /a>>nestvar.bat
command /c call nestvar>putfile.nst
  可以改为:
echo dir "%%dir%get%%%\%wbat%" /a %"%>%"%putfile.nst>>nestvar.bat
call nestvar.bat
  
作者: GOTOmsdos     时间: 2005-4-29 00:00
确实是这样的. 以前有过 想ECHO 这个>重定向符号,一直没解决,
刚在VWARE里试过,不行,是不是一定要在纯DOS下才行?
echo dir "%%dir%get%%%\%wbat%" /a %"%>%"%putfile.nst>>nestvar.bat
call nestvar.bat
以上, 确定没错吗?

[此贴子已经被作者于2005-4-29 21:16:35编辑过]



作者: willsort     时间: 2005-4-29 00:00
Re GOTOmsdos:
  抱歉,太匆忙了,犯了同样的错误。主要还是利用%的转义特性。
echo @echo off>nestvar.bat
echo dir "%%dir%get%%%\%wbat%" /a>>nestvar.bat
command /c call nestvar>putfile.nst
改为
echo dir "%%dir%get%%%\%wbat%" /a %%"%%>%%"%%putfile.nst>nestvar.bat
call nestvar.bat

[此贴子已经被作者于2005-4-29 23:24:50编辑过]



作者: GOTOmsdos     时间: 2005-4-30 00:00
哦, 试过了,不错! 精彩! 发现""号不能换成别的符号吧?多谢!
作者: chenhui530     时间: 2005-4-30 00:00
不错啊~几天没来差点错过这样好的文章啊~确实精彩
作者: mtiankong     时间: 2008-11-3 20:17
收获大~~~~