Board logo

标题: SOS!!!!!!请教关于变量延迟!! [打印本页]

作者: yuanzijia08     时间: 2006-11-4 14:30    标题: SOS!!!!!!请教关于变量延迟!!

setlocal EnableDelayedExpansion
set m=0
for /f "tokens=*" %%m in ('findstr /v /C:"730 730" cover.ps') do (

    if !m! == 686 (pause) else (echo %%m >>cover3.txt)
set /a m=!m! + 1
   
)

paus
exit


这是kcdsw兄弟写的一个批处理  他自己说有以下问题     
  
  如果使用set 再echo 那么文本中的%会被替换掉.  
  如果使用call,而不启用变量延迟,将for的%%m传递给call的时候同样会丢失东西
  所以我还是启用了变量延迟,所造成的结果就是! 都不见了 希望高手赐教

我想先暂且不论这些问题
想请高手 依据这个例子  解释下变量延迟  是怎么个延迟法  为什么要延迟

我从上面的“如果使用call,而不启用变量延迟,将for的%%m传递给call的时候同样会丢失东西”这句话 猜想 是因为两个段之间传递不了参数 而使用变量延迟   网上查了好多也没有完全理解 变量延迟  所以想请高手着重讲下

[ Last edited by yuanzijia08 on 2006-11-4 at 02:31 PM ]
作者: yuanzijia08     时间: 2006-11-4 14:35
@echo off
set m=0
for /f "tokens=*" %%m in ('findstr /v /C:"730 730" cover.ps') do (
    set line=%%m
    call :Output
    set /a m+=1
)
pause
exit

:Output
if "%m%" == "686" (pause) else (echo %line% >>cover3.txt)
goto :eof


这个是一位大哥为帮助 kcdsw 解决问题而帮他改写的   是关闭了变量延迟  而使用了call  想请高手依据这两个例子来说说  启用了变量延迟和  关闭变量延迟有什么不同

万分感谢!!!!
作者: namejm     时间: 2006-11-4 16:16
  本版精华有这个问题的答案,何必要到外面去找呢?请看:什么情况下该使用变量延迟?
作者: yuanzijia08     时间: 2006-11-4 22:47
精华版的教程绝对不适合初学者   我是看了好多遍才来问的  我个人觉得还是要以一个事例来分析更好
我先假设程序实在这样的:(比原程序少了个setlocal EnableDelayedExpansion
, 就是不起用变量延迟)
set m=0
for /f "tokens=*" %%m in ('findstr /v /C:"730 730" cover.ps') do (

    if !m! == 686 (pause) else (echo %%m >>cover3.txt)
set /a m=!m! + 1
   
)

paus
exit

精华版里面有这几句话
命令解释器扩展环境变量的行为大致如下:首先读取命令行的一条完整语句,在进行一些先期的预处理之后,命令被解释执行之前,会对其中用百分号闭合的字符串进行匹配,如果在环境空间中找到了与字符串相匹配的环境变量,则用其值替换掉原字符串及百分号本身,如果未得到匹配,则用一个空串替换,这个过程就是环境变量的“扩展”,它仍然属于命令行的预处理范畴。

在进行一些先期的预处理之后  命令被解释执行之前,会对其中用百分号闭合的字符串进行匹配

这不就是在
for /f "tokens=*" %%m in ('findstr /v /C:"730 730" cover.ps') do (

    if !m! == 686 (pause) else (echo %%m >>cover3.txt)
set /a m=!m! + 1
)
这个语句执行之前 会对其中用百分号闭合的字符串进行匹配吗?
那不就行了嘛  for语句读第一行 ('findstr /v /C:"730 730" cover.ps')这个数据的时候m=0  然后m=1 2 3....... 只要在  if !m! == 686 (pause) else (echo %%m >>cover3.txt)执行之前把!m!  用其值替换掉   这有什么不对? 为什么还要开启变量延迟呢?
开启了变量延迟   这个程序又是怎么一步一步执行的?
作者: namejm     时间: 2006-11-4 23:07
  既然用了 !m! 的格式,也就意味着开启了变量的延迟功能,所以,setlocal EnableDelayedExpansion 语句绝对不能少,否则,CMD是无法解析 !m! 的。
作者: willsort     时间: 2007-1-20 08:32
Re yuanzijia08:

      从以上的讨论来看,兄确实对“变量延迟替换”进行了较深入的思考。

      兄的误区在于没有彻底理解我在原文档中所提到的“完整的语句”概念。

      也就是说,对于解释执行批处理的cmd来说,下面的代码只是“一条”语句,我们可以称它为“复合语句”,当然微软官方并没有这样称呼。

for /f "tokens=*" %%m in ('findstr /v /C:"730 730" cover.ps') do (
    if !m! == 686 (pause) else (echo %%m >>cover3.txt)
    set /a m=!m! + 1
)

      而在这一条语句被解释执行之前,所有的%都被进行了转义替换,包括%%m也被替换成了%m。而其中如果有%m%,也会直接替换成一个相对固定的“常量”,而不再是一个变量了;也就是说,无论for内部再对变量m做任何改变,都只能在for语句执行完后才能感知出来,在for内部%m%已经不再变化了。

      但实际情况是,我们往往需要感知一个变量在for语句中动态变化,因为我们需要利用这些变化完成一些应用实现。所以,cmd才引入了延迟扩展的机制和专用的转义符号!。

      此时,cmd对%的处理仍遵循以上所述的机制,只是对原来并不处理的!!括起来的变量进行了另一种方式的解析。cmd在分析for语句时,仍然是进行“整句”读入、预处理、变量扩展等工作,然后开启for语句内部的处理流程,相当于利用一个精简的cmd循环执行另外一个批处理,在这个流程中,将对在for之外并不作任何处理的!!字符串,做类似%%的变量扩展,这个扩展过程与解释一个普通的批处理文件相类似。

      简而言之,启用延迟前,在()内的代码被执行之前,代码中的所有变量就已经完成了替换;而启用延迟后,替换工作则延迟到了()中每条语句执行之前。

      同样的工作机制存在于if/else复合语句,任何用()括起的复合语句以及用|、&、&&、||连接起来的复合语句中。

      另外需要说明的是,cmd中的变量也存在全局与局部的区别,只是这种区别并非以()这种类似C语言的语句块作为分界的。比如说,我们在for语句中定义了一个变量,那么在for执行结束后,这个变量则仍然是存在的。这与我们所讨论的变量延迟扩展并无实质上的联系。

[ Last edited by willsort on 2007-1-20 at 09:23 AM ]
作者: electronixtar     时间: 2007-1-20 08:34
沙发,占个位置瞻仰willsort的帖子

[ Last edited by electronixtar on 2007-1-20 at 08:41 AM ]
作者: vkill     时间: 2007-1-20 08:44
willsort 的帖子看了受益非浅
作者: everest79     时间: 2007-1-20 09:03
有好些东西,你明白,但就讲不出来,这就是工匠与大师的区别
                                                           -------小泥水匠everest79