Board logo

标题: 批处理中的for命令原理图示 [打印本页]

作者: myzwd    时间: 2009-3-2 13:21     标题: 批处理中的for命令原理图示

  1. @echo off
  2. for /l %%1 in (0 1 2) do (
  3. set x=%%1
  4. call,echo %%x%%
  5. pause >nul
  6. echo ok
  7. )
复制代码
上述代码运行显示如下----
0
暂停
ok
1
暂停
ok
2
暂停
ok


---------------------------
    网上看到不少关于call echo的说法的,最多的说法是,脱%论。但我觉得,脱%论,应该算是语法的范畴,与for的运行原理无关。那只是表象。也许你会说堆栈是后进先出,是的,你注意没有,for中堆栈里面始终就只有一个数据。这让我明白了。延迟环境变量,就是启用堆栈。
   我认为----call echo是----call ,echo的简写,其运行原理应该与堆栈有关。“call ,echo”就是用了空标号原理。
那么空标号成立吗?
  你验证下面的代码吧:
  1. @echo off
  2. echo ok 1
  3. call ,
  4. echo ok 2
复制代码
这点和setlocal enabledelayedecpansion的原理相同。下面把for 。。。call echo的流程图示如下:



----------------在讨论中进步------错对不重要 重要的是参与-----争取每天都有一点点收获------------------------------------------------------------------------------
  从for想到的 再解释机制--在此提出共商讨--
     观点如下
1---cmd是以解释方式执行命令的,即机器翻译一条,执行一条,如此反复,直到完成程序。
2---cmd在解释程序中的一条(注意是一条)语句时,一定是,一定是!!!预先把语句中的数据匹配好之后,
    才开始执行。
3--如果是一个语句块,里面又有语句块,cmd就会对小语句块再做出解释。这就是我的观点。
  
4--实例分析:
   我----
@echo off
set tt=123
if 2==2 (
   set tt=222
   echo %tt%  
   call echo %%tt%%
)
分析:这里就是语句块套语句块,cmd在解释if语句时,遇到里面的小语句块call echo %%tt%%,
      就对它进行再解释。当这些解释都完成后,cmd才算就完成了对if语句的解释。最后执行if语句。  
    显见call只会抓取离它最近的set变量数据。这样就说明了if体内数据为什么会变。
      
    的---
@echo off
set tt=123
for %%1 in (0 1 2) do (
   set tt=222
   echo %tt%  
  echo %tt%
   echo ----------
)
分析:我认为的理由同上---语句块套语句块,为了数据的匹配,for对子语句块做出再解释。
5---延迟变量
  我的观点是开启延迟变量后,就推迟(延迟)for主语句体的执行,因为,cmd要再次解释
for体内部的延迟变量!tt!,再解释是要花费“时间”的,for的执行就被推迟了。所以就叫
延迟了。在解释for体内的!tt!变量时,这个变量总是抓取离它最近的set 所定义的值。
   关----
@echo off
setlocal enabledelayedexpansion
set tt=123
for %%1 in (0 1 2) do (
   set tt=222
   echo %tt%  
   echo !tt!
   echo ----------
)
这样看来"echo !tt!" 。被再解释了。

[ 本帖最后由 myzwd 于 2009-3-3 15:24 编辑 ]
作者: lhjoanna    时间: 2009-3-2 21:03

楼主的图画的很晕啊,不过我还是细细的看了一遍。提出几个疑问:
<1>call空标号的说法有何依据?空标号原理是什么?
<2>上面提到的堆栈是用来存放什么数据的?for堆栈又指什么?
<3>"延迟环境变量,就是启用堆栈"又有什么根据?
我的看法:
<1>对于上述例子中的call , 可以运行的情况。楼主认为是空标号。既然是空标号,楼主又加个逗号是何意?加了逗号还是空标号吗?我测试过call后加空格,逗号,分号都可以正确运行。并且空格,逗号,分号都是批处理的分隔符。for对文本或文件解析时delims默认为空格和逗号,eol默认为分号。并且使用call做调用子程序用时都需要加冒号的。
<2>楼主说call,echo %%x%% 时,首先把0入栈,然后发觉是空标号,所以就又出栈。这样做有何意义?换个角度,从底层来看,每次调用子程序过程中,call包含两层意思:首先把当前指令的段地址与偏移地址入栈,其次执行跳转指令,也就是跳转到标签所在的地址。并且子程序结束后会有一个 goto :eof,表示子程序结束。这个goto :eof也就是之前入栈的地址出栈,程序接着上面调用子程序的下一条执行。由此看来,入栈的原因是保护现场,需要入栈的是指令的地址,而不是程序需要处理的数据。
<3>"延迟环境变量,就是启用堆栈",这样的说法我头一次听说。对于for中遇到开启变量延迟的变量就入栈的说法,不知具体有什么思考、根据。
<4>我想这又涉及到一个call与变量延迟机制的问题,想要完全弄明白还需要从机制入手。对于楼主的行为我表示肯定,我想这也会吸引更多的人来参与讨论的。一个新理论的提出确实需要来自多方面的检验。
附:一个简单的例子,就是查看开启变量延迟和使用call后的执行时间对比。
  1. @echo off&setlocal enabledelayedexpansion
  2. set str=123
  3. echo %time%
  4. for /l %%i in (1,1,10000) do echo %str%>nul
  5. echo %time%
  6. for /l %%i in (1,1,10000) do echo !str!>nul
  7. echo %time%
  8. for /l %%i in (1,1,10000) do call echo %%str%%>nul
  9. echo %time%
  10. pause
复制代码

作者: myzwd    时间: 2009-3-2 22:36     标题: 回复 2楼 的帖子

这中间 需要讨论的太多。还望大家参与。无论错对,都会提高对for和延迟变量的认识。你的代码我运行了,时间不一样,call明显的慢,但这说明不了数据的流程啊
  1. @echo off
  2. setlocal enabledelayedexpansion
  3. echo %time%
  4. for /l %%i in (1,1,500) do echo 111>nul
  5. echo %time%
  6. endlocal
  7. pause
  8. echo %time%
  9. for /l %%i in (1,1,500) do call echo 111>nul
  10. echo %time%
  11. pause
复制代码
延迟块的原因是我猜是没有set变量在for体内的传递。



    我突然想起了call echo这个结构看起来多象调用外部的批处理啊。---批处理函数。对就是它
@echo off
call mybatchfilesname
goto:eof

------------------
外部文件
----mybatchfilesname.bat-
echo 123456789
----------------------------

这个call echo中的echo不就相当与外部的批文件吗,调用外部的文件当然要慢点啊
这更能证明是堆栈的原理了。调用外部文件可以跟参数,call echo后面可以跟环境变量,这中间是什么关系呢?晕。
   你们的论坛真的不错。我来这里是学习的,以前我没想到批处理可以编制那么好玩的程序。来这里我学到了不少东西。

[ 本帖最后由 myzwd 于 2009-3-2 23:42 编辑 ]
作者: lhjoanna    时间: 2009-3-2 23:09     标题: 回复 3楼 的帖子

恩,楼主也说了,call明显速度变慢。这也就是我说的意思,这就引出一个疑问:为什么会变慢?call echo的机制是什么?
作者: zqz0012005    时间: 2009-3-2 23:25

楼主不会是联盟的5yue5吧。

http://www.cn-dos.net/forum/viewthread.php?tid=46415
作者: Batcher    时间: 2009-3-2 23:33     标题: 回复 5楼 的帖子

看到“堆栈”二字的时候,我也是这样联想的^_^
作者: irresolute    时间: 2009-3-4 08:14     标题: 随便说二句

call,echo %%x%% 豆号其实就是分隔符,可改为空格,call也具有变量延迟的功能。
作者: wbh    时间: 2010-8-27 08:27

我找到了答案 关于CALL 的用法,请参考http://ss64.com/nt/call.html
关于 FOR 命令中CALL 的用法,请参考http://www.dostips.com/DtTipsFtpBatchScript.php#Batch.FtpBatchUsingVariables
都是英文的,我已经翻译成了中文,请参考http://hi.baidu.com/wangbaohua3/blog/item/bdba8f66be4cefd3e6113a60.html
作者: zhlg9782    时间: 2010-10-7 19:28

看看!
作者: ai20110304    时间: 2018-8-28 15:24

回复 8# wbh


    谢谢分享这么好的网站




欢迎光临 批处理之家 (http://bbs.bathome.net/) Powered by Discuz! 7.2