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
以下是引用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' 的开始标志,仍然无法实现你原定的意图。   解决的方法很简单,现在比较忙,没有多少时间详细解释。现给你一个实例,相信不难看懂的,主要还是利用%的“逃逸”特性,只不过“逃逸”的顺序有所不同。
:: 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
收获大~~~~