Board logo

标题: 批处理中的if defined 需知 2009-5-10 更新 [打印本页]

作者: 随风    时间: 2008-10-3 10:41     标题: 批处理中的if defined 需知 2009-5-10 更新

if defined 需知
:: code 随风 @bbs.bathome.net 2008-10-01
if defined 命令 使用需注意的地方。
我们经常使用 if defined 命令来判断某个变量是否被定义过。这个命令非常有用,使用频率也颇高。
但是 if defined 确有些错误的用法容易被忽略,个人曾吃过亏,费了九牛二虎之力才找到出错原因。
也许各路高人早以心知肚明,但网上却好像很少有人讨论。(也许是我孤陋寡闻了,呵呵)
现就个人经验作个总结,知道的一笑而过,不知道的可以少走些弯路。
错误的欢迎指出。。。
问题一: 空格问题。
测试  代码 1-1
  1. ::代码 1-1
  2. @echo off
  3. set ab cd=fff
  4. if defined ab cd (echo ab cd 被定义了) else echo ab cd 没有被定义
  5. pause
复制代码
什么都没显示,直接执行后面的 pause 命令了,按说应该显示 “ab cd 被定义了”才对呀。
问题出在空格上
总结: if defined 这里不能有空格。
再测试  代码 1-2
  1. ::代码 1-2
  2. @echo off
  3. set ab cd=fff
  4. set "var= "
  5. if defined ab%var%cd (echo ab cd 被定义了) else echo ab cd 没有被定义
  6. pause
  7. [code]
  8. 我们把空格用变量来代替,结果还是一样,郁闷!难道就不能检测含空格的变量名是否被定义过吗?
  9. 不信邪,继续。。。
  10. 测试 代码 1-3
  11. [code]
  12. ::代码 1-3
  13. @echo off
  14. setlocal enabledelayedexpansion
  15. set ab cd=fff
  16. set "var= "
  17. if defined ab!var!cd (echo ab cd 被定义了) else echo ab cd 没有被定义
  18. pause
复制代码
乖乖,你终于出来了。。。!
再试试多个空格时如何?测试代码 1-4
  1. ::代码 1-4
  2. @echo off
  3. setlocal enabledelayedexpansion
  4. set a b c d e=fff
  5. set "var= "
  6. if defined a!var!b!var!c!var!d!var!e (
  7.   echo a b c d e 被定义了
  8. ) else echo a b c d e 没有被定义
  9. pause
复制代码
哈哈,真的可以。。。
但是这样似乎也太麻烦了点。!!若是含多个空格,岂不是要写上一大堆的变量??
试试将变量名赋值给别的变量试试。。
看 代码 1-5
  1. ::代码 1-5
  2. @echo off
  3. setlocal EnableDelayedExpansion
  4. set ab cd=fff
  5. set "var=ab cd"
  6. if defined !var! (echo ab cd 被定义了) else echo ab cd 没有被定义
  7. pause
复制代码
嗯,果然可以。。这下简单多了。。。
但是需注意的是仍然得用!!来引用变量。
总结:
   检测含空格的变量名是否被定义过,需开启延迟变量,
   并把 if defined 这里的所有空格都用变量来代替
   或是将变量名赋值给别的变量,再用!!来引用这个新的变量。
再试试  代码 1-6
看看在 for 中是否能行?感觉应该是可以的,因为for的 %%i 也是变量啊。
试试再说。。
  1. ::代码 1-6
  2. @echo off
  3. set a b c d=fff
  4. for /f "delims=" %%i in ("a b c d") do (
  5.    if defined %%i (echo %%i 被定义了) else echo %%i 没有被定义
  6. )
  7. pause
复制代码
果然可以,而且可以不用开启变量延迟。
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
问题二: 变量的截取。
先看一段代码
  1. ::代码 2-1
  2. @echo off
  3. setlocal EnableDelayedExpansion
  4. set a=fff
  5. set var=abc
  6. if defined !var:~0,1! (echo a 被定义了) else echo a 没有被定义
  7. pause
复制代码
居然又是老问题 ???!!!
明明开启了延迟变量啊。。!
试试不用变量的延迟扩展看看
  1. ::代码 2-2
  2. @echo off
  3. setlocal EnableDelayedExpansion
  4. set a=fff
  5. set var=abc
  6. if defined %var:~0,1% (echo a 被定义了) else echo a 没有被定义
  7. pause
复制代码
可以了,还真是麻烦,忽左忽右、忽上忽下的,头的晕了。。。
那么在 for 中呢?
代码 2-3
  1. ::代码 2-3
  2. @echo off
  3. setlocal EnableDelayedExpansion
  4. set "a=fff"
  5. set "b=fff"
  6. set "c=fff"
  7. set "var=abc"
  8. for /l %%i in (0 1 2) do (
  9.   if defined !var:~%%i,1! (echo a 被定义了) else echo a 没有被定义
  10. )
  11. pause
复制代码
竟然一闪而过,语法错误了。。汗。。!
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
最后总结:
   用 if defined 判断某个变量是否被定义过时需注意以下2点:
   1、不能直接输入空格,有空格时需用变量来代替,且必须是用双!!来引用这个值含空格的变量
      也就是必须开启延迟变量,或者将需判断的变量名赋值给 for 的 %%i 变量。
   2、若判断的变量名需要使用变量的字符截取功能时,则与上面的正好相反。
      即:不能使用!!来引用变量,即使是在for中也是一样。

更新:但可以 if defined !num:~1! 或 if defined !num:~-1!
         不能同时指定两个数字,或者说不能出现逗号。

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

[ 本帖最后由 随风 于 2009-5-10 12:44 编辑 ]
作者: yslyxqysl    时间: 2008-10-3 14:58

哈哈,我从来都是用if not "%var%"==""
作者: Batcher    时间: 2008-10-3 21:16

授人以鱼,不如授人以渔。
随风 兄何不从批处理的执行机制等方面入手,讲解一下为什么会出现这些问题?
作者: zqz0012005    时间: 2008-10-3 21:33

与变量含空格类似,还有变量值含引号的问题
  1. @echo off
  2. >a.txt echo "
  3. set var="
  4. setlocal EnableDelayedExpansion
  5. for /f %%a in (a.txt) do (
  6.         if %var:"=quote%==quote echo equal
  7.         if "%var:"=quote%"=="quote" echo equal
  8.         rem if !var:"=quote!==quote echo equal
  9.         rem if "!var:"=quote!"=="quote" echo equal
  10.         if "%%a"=="!var!" echo equal
  11.         rem if "%%a"=="%var%" echo equal
  12. rem 注释掉的语句会出错
  13. )
  14. pause
复制代码
3楼提出的问题可以参考此贴:
简析环境变量和变量延迟特殊字符以及中介法的微妙关系
http://www.cn-dos.net/forum/viewthread.php?tid=30884
作者: youxi01    时间: 2008-10-3 23:13

呵呵,随风兄的研究果真不一般啊
我遇到这样的问题,一般都是避过(为什么不弄一个没有空格的变量名呢?),惭愧,惭愧!
作者: Batcher    时间: 2008-10-3 23:24     标题: 回复 4楼 的帖子

感谢版主的热心,3楼并非问题,只是建议^_^
bjsh 兄的帖子我很早前也看过,还有你们在verybat讨论预处理等相关内容的帖子我也看过,写的都挺好。这里只是建议楼主在我们bathome也做一下深入的讲解,呵呵。
作者: 随风    时间: 2008-10-7 01:45

原帖由 Batcher 于 2008-10-3 21:16 发表
授人以鱼,不如授人以渔。
随风 兄何不从批处理的执行机制等方面入手,讲解一下为什么会出现这些问题?

非常遗憾,对命令机制的问题,我也是知其然,不知其所以然。。。

[ 本帖最后由 随风 于 2010-9-2 11:06 编辑 ]
作者: firewolf85    时间: 2008-12-10 19:54

万恶的空格,做wxcute 版主的中级练习题时花了1个多小时调试,最后发现多了个空格,哎
作者: zjw767676    时间: 2009-4-7 23:16

请随风版主测试以下代码
  1. @echo off
  2. setlocal EnableDelayedExpansion
  3. set "ab cd= "
  4. set "var=ab cd"
  5. if defined !var! (echo ab cd 被定义了) else echo ab cd 没有被定义
  6. pause
复制代码
个人认为这里判断的是变量var而不是ab cd

[ 本帖最后由 zjw767676 于 2009-4-7 23:39 编辑 ]
作者: 随风    时间: 2009-4-7 23:23     标题: 回复 9楼 的帖子

不知道你想说明什么?
我运行你的代码显示 ab cd 被定义了
这和我顶楼说的不相违背啊?你的代码把 ab cd 定义了一个空格,不知道你是故意的还是无意的。若是有意的应加上引号,否则很容易让人误解。
作者: zjw767676    时间: 2009-4-7 23:43

我的意思是这样不能判断变量ab cd是否为空!
引号已加,感谢指正!!!!
作者: 随风    时间: 2009-4-7 23:47     标题: 回复 11楼 的帖子

凭什么说你的代码不能判断变量ab cd是否为空
代码中 ab cd 本来就不是空,当然会显示 ab cd 被定义了,有什么错?
作者: zjw767676    时间: 2009-4-8 00:03

  1. @echo off
  2. setlocal enabledelayedexpansion
  3. set "ab cd="
  4. ::未赋值
  5. set "var= "
  6. if defined ab!var!cd (echo ab cd 被定义了) else echo ab cd 没有被定义
  7. pause
复制代码
显示没有定义
下面的代码无论是否赋值给ab cd都显示被定义了
  1. @echo off
  2. setlocal EnableDelayedExpansion
  3. set "ab cd="
  4. set "var=ab cd"
  5. if defined !var! (echo ab cd 被定义了) else echo ab cd 没有被定义
  6. pause
复制代码
不知随风版主理解我的意思了吗?

[ 本帖最后由 zjw767676 于 2009-4-8 00:12 编辑 ]
作者: 随风    时间: 2009-4-8 00:09

原帖由 zjw767676 于 2009-4-8 00:03 发表

下面的代码无论是否赋值给ab cd都显示被定义了

1、你确定你的第二个代码无论是否赋值给ab cd都显示被定义了吗?
2、加对引号就这么难吗?
作者: zjw767676    时间: 2009-4-8 00:09

晕了,搞错了!
两次运行结果不一样!
是我这边出问题了!
麻烦随风版主了!
总结了下:
都是坏习惯惹的祸!
第一次测试时无意之中在=号后加了个空格
以为没赋值给变量!


再次感谢随风版主,今后一定改掉所有坏习惯!不能偷懒少了引号!

[ 本帖最后由 zjw767676 于 2009-4-8 00:24 编辑 ]
作者: yadngah1984    时间: 2010-9-20 14:30

感谢版主授教,学了不少!
作者: wangx    时间: 2013-9-16 16:28

讨论的很细致啊。
作者: ai20110304    时间: 2018-8-28 17:01

绕晕        底层!!和%%的区别。。。。   我的理解是!!作解析比%%更晚,所以在if执行期间取得相应的变量名。而%%在执行批处理之前,先进行了%%的预处理(变量替换)。




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