中国DOS联盟论坛

中国DOS联盟

-- 联合DOS 推动DOS 发展DOS --

联盟域名:www.cn-dos.net  论坛域名:www.cn-dos.net/forum
DOS,代表着自由开放与发展,我们努力起来,学习FreeDOS和Linux的自由开放与GNU精神,共同创造和发展美好的自由与GNU GPL世界吧!

游客:  注册 | 登录 | 命令行 | 会员 | 搜索 | 上传 | 帮助 »
中国DOS联盟论坛 » DOS批处理 & 脚本技术(批处理室) » 环境变量延迟扩展的五种常用方法
作者:
标题: 环境变量延迟扩展的五种常用方法 上一主题 | 下一主题
q8249014
初级用户





积分 175
发帖 45
注册 2007-8-4
状态 离线
『楼 主』:  环境变量延迟扩展的五种常用方法

@echo off
:: Code q8249014
:: 环境变量延迟扩展的五种常用方法
:: 补充一种cmd /c
(
  set "var=test"
  cmd /c echo %%var%% 调用新的命令解释器进行延迟 
  call echo %%var%% call延迟
  <nul set/p=|echo %%var%% 管道延迟
  for /f %%i in ('echo %%var%%') do echo %%i for延迟
  setlocal enabledelayedexpansion
  echo !var! 启用延迟环境变量扩展
)
set/p= 请按回车键继续. . .
[ Last edited by q8249014 on 2010-1-20 at 21:44 ]


   此帖被 +22 点积分          点击查看详情   
评分人:【 bat-zw 分数: +20  时间:2010-1-11 16:22
评分人:【 sl543001 分数: +2  时间:2010-1-21 00:23


2010-1-10 15:31
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
bat-zw
金牌会员

永远的学习者


积分 3105
发帖 1276
注册 2008-3-8
状态 离线
『第 2 楼』:  

精品,学习了。




批处理之家新域名:www.bathome.net
2010-1-11 16:23
查看资料  发送邮件  发短消息 网志  OICQ (841615149)  编辑帖子  回复  引用回复
bat-zw
金牌会员

永远的学习者


积分 3105
发帖 1276
注册 2008-3-8
状态 离线
『第 3 楼』:  

我再跟一个:
:: 利用set延时
@echo off
(
set "#a=cn-dos"&set #
for /f "tokens=2 delims==" %%a in ('set #') do echo %%a
)
pause>nul




批处理之家新域名:www.bathome.net
2010-1-11 16:55
查看资料  发送邮件  发短消息 网志  OICQ (841615149)  编辑帖子  回复  引用回复
zqz0012005
中级用户




积分 297
发帖 135
注册 2006-10-21
状态 离线
『第 4 楼』:  

管道机制 bbs.verybat.org ... for /f 机制 www.bathome.net ...




2010-1-12 00:05
查看资料  发短消息 网志  OICQ (411976538)  编辑帖子  回复  引用回复
q8249014
初级用户





积分 175
发帖 45
注册 2007-8-4
状态 离线
『第 5 楼』:  

回4f: 你所提供的2篇帖子都是非常不错的。“预处理和管道”中关于管道机制的探索确有独到之 处,但也存在不足,比如“pause|pause”为什么提示“过程试图写入的管道不存在。”, 而“set/p=t|pause”却正常,这里提及一点,pause的标准输出是 “请按任意键继续. . . 加上一个回车”,而set/p=t的标准输出为t,那么请测试“<nul pause|pause”,是不是正 常了,管道的问题就提到这里。因为我准备写一篇关于管道机制的帖子,所以关于管道机制 的其他问题在以后的帖子中再说吧。 “批处理脚本高级编程技巧——变量嵌套”中也没有讲到for是如何实现变量延迟扩展的, 你在2f中也只是简单比喻了下,一些朋友可能还是不知道原理。那么,下面就再说说for。 首先提及一点,for命令没有单独的命令处理模块,它和预处理共用一个命令分析处理模 块。在预处理过后,控制权交给for,当for进行一些格式匹配解释后,它会在调用一个新 的命令解释器将('command')中的命令提交该解释器解释执行,然后将执行结果传递给for 继续for命令的执行,下面以几个实例演示一下。
@echo off
for /f "delims=" %%i in ('echo.%%cmdcmdline%%') do (echo.%%i)
pause
从上面这段代码中可以看出for新调用的命令解释器为“C:\WINDOWS\system32\cmd.exe /c echo.%cmdcmdline%” 既然调用了新的命令解释器,那么预处理自然必不可少,从而就达到了延迟扩展的目的。
@echo off
for /f %%i in ('dir /b /ad %%windir%%^|find /v " "') do (echo.%%i)
pause
上面这段代码是一段很经典的过滤代码,目的是打印windows目录下的所有目录名但不打印含空格的目录名,试想 一下,如果('command')中的命令不再调用新的解释器解释而是直接执行,那么命令将会变成这个样子: dir /b /ad %windir%|find /v " " 出现错误提示:无效的命令行开关 - "v"。 上面所说的 “set/p=t|pause” 只是为一个演示,其实我们还可以构造一个空传递,“<nul set/p=|pause” 同时也更新了顶楼的代码,使之更有趣一些 补充一下管道的原理: 管道1|管道2|管道3 以管道符为分割符,首先启动最后面一个命令(管道3),然后是倒数第二个(管道2),依此类推,然后 后一个命令会暂停以接收前一个命令的输出,如果命令输出为空则直接退出。 即:管道2接收管道1,管道3接收管道2, 最后,感谢2f的加分与肯定


2010-1-20 21:46
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
deepimpact
新手上路





积分 3
发帖 2
注册 2008-12-12
状态 离线
『第 6 楼』:  

q8249014兄对管道很有研究,有个问题想请教一下
set/p<nul=1|findstr .
会输出"1\n"
set/p<nul="1"|findstr .
却没有输出 不知是何原因


2010-4-4 16:29
查看资料  发短消息 网志   编辑帖子  回复  引用回复
zaixinxiangnian
初级用户





积分 151
发帖 106
注册 2009-10-9
来自 河南省
状态 离线
『第 7 楼』:  

zqz0012005 q8249014 你们提到这些都非常经典,不过对于我们这些初学批处理的来说有点难理解


2010-4-4 20:02
查看资料  发送邮件  访问主页  发短消息 网志  OICQ (657614933)  编辑帖子  回复  引用回复
HAT
版主





积分 9023
发帖 5017
注册 2007-5-31
状态 离线
『第 8 楼』:  Re 7 楼

很正常。 人家学了那么多年才有这点功底,你初学就像一下都搞清楚? 大家都不是天才,踏踏实实学,慢慢会理解的。




2010-4-5 10:39
查看资料  发短消息 网志   编辑帖子  回复  引用回复
q8249014
初级用户





积分 175
发帖 45
注册 2007-8-4
状态 离线
『第 9 楼』:  

Re 6F 1.在回答之前我们先来看一下 findstr 输出的方式 开始-----运行-----cmd.exe-----findstr .-----a-----\r-----b-----\r------F6-----\r 在看一下 find 开始-----运行-----cmd.exe-----find /v ""-----a-----\r-----b-----\r------F6-----\r 以上的输出有什么不同你们自己比较一下 2.
@echo off
echo test|(pause&findstr .)
set/p= 请按回车键退出. . .
仔细想一下上面这段代码为什么会出现这种情况? [test-----est]? 3.set/p<nul=1|findstr . --------------- ok 那么它的标准输出是你所说的 "1\n"吗?我们用下面的代码检验一下 set/p<nul=1|^> test.txt findstr . 到底对不对请看test.txt 4.你知道 [<nul set/p=test] 和 [<nul set/p="test" QQ] 的区别吗? 请执行一下试试 5.下面我们来看一下3中的原因 set/p<nul=1|findstr . 这句代码经过命令解释器第一次解释之后变为 [set/p=1 0<nul] 好就点到这里 现在明白多出的一个空格来自何处了吧 6.[set/p<nul="1"|findstr .] -------------- no [set/p<nul="12"|findstr .] --------------- ? [set/p<nul="1"|find /v ""] --------------- ok 第6点请你们根据1-5条的讲解自行分析一下,关键点我都已经提出了。 提示:问题出在 findstr 上 ps:由于没有官方文档的支持,所以上内容仅供参考。 由于最近上网时间少所以前几天才看到各位的回复,O(∩_∩)O~


2010-5-1 18:00
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
qzwqzw
银牌会员

天的白色影子


积分 2343
发帖 636
注册 2004-3-6
状态 离线
『第 10 楼』:  

楼主老兄喜欢举例来说明问题 可惜有些问题仍然没有说透彻 5楼提到的pause|pause问题 是因为后一个pause首先输出“请按任意键继续. . .”后等待管道输入 前一个pause输出“请按任意键继续. . .”(不包含换行)送入管道 后一个pause将第一个字作为暂停确认 其它的字符则被丢弃 此时后一个pause作为管道的接收方就结束了 而前一个pause在稍后时候接收到用户的输入后 会再输出一个换行符 而这个输出此时找不到管道的接收方 自然会提示“过程试图写入的管道不存在。” 而pause<nul|pause正常 是因为前一个pause不再需要用户输入 而连带换行符一起输出 并通过管道交给后一个pause 此时第一个pause就已经结束 不再对管道进行再次写入 for /f %%i in ('dir /b /ad %%windir%%^|find /v " "') do (echo.%%i) 这个例子实际并不太好 因为也完全可以这样写 for /f %%i in ('dir /b /ad %windir%^|find /v " "') do (echo.%%i) 变量嵌套一般不这样使用 而是这样 set var=value set varname=var for /f %%i in ('echo %%%varname%%%') do (echo.%%i) 9楼的第1节是说findstr从标准输入匹配文本不可靠 可能会造成匹配的延迟 由于没有官方文档其规律难以掌握 而find则是正常的 第2节是说pause吞吃了管道中的第一个字符"t"作为暂停继续的确认字符 第3节和第5节是说set/p的输出没有回车换行 因为管道前出现了& < 等特殊符号 所以预处理为处理这些符号而插入的空格没有过滤就被送进管道了 第4节的是说set对双引号对的特殊处理 即参数中有双引号对就只处理其中的内容 而忽略引号对外的其它内容 第6节 set/p<nul=1|findstr . <nul导致多插入一个空格 所以set的输出为1空格 set/p<nul="1"|findstr . set只处理引号对中的内容 所以输出为1 set/p<nul="12"|findstr . set只处理引号对中的12 所以输出为12 set/p<nul="1"|find /v "" find匹配正常匹配


2010-5-1 23:42
查看资料  发短消息 网志   编辑帖子  回复  引用回复
gudou
初级用户





积分 43
发帖 29
注册 2008-3-31
状态 离线
『第 11 楼』:  

都是达人级的……小可拜上学习


2010-5-2 13:39
查看资料  发短消息 网志   编辑帖子  回复  引用回复
q8249014
初级用户





积分 175
发帖 45
注册 2007-8-4
状态 离线
『第 12 楼』:  

RE 10F 5f的回复主要是针对4f的,所以只是点了一下,你对 pause|pause 的理解和我当初所理解的一样 for /f "delims=" %%i in ('echo.%%cmdcmdline%%') do (echo.%%i) 你说上面这个例子并不太好,可能是你没有仔细看5f的内容,以上例子是为了说明 ('command')中的代码会进行2次预处理,你可以回看一下5f 9f的第一节是为了说明findstr和find输出时的区别,也是为了后面的 [command|findstr .] 做铺垫 第二节你理解正确 第3节和第5节我们放着后面再说 第四节也对 第六节中我给出的代码你可能都没有测试 [set/p<nul="1"|findstr .] -------------- no [set/p<nul="12"|findstr .] --------------- ? [set/p<nul="1"|find /v ""] --------------- ok ————————————— set/p<nul="1"|findstr . set只处理引号对中的内容 引用qzwqzw 所以输出为1 ————————————— 以上引用是没有输出的 好,说到这里你们应该可以明白3、5节的意识了 由于没有官方文档的支持,所以不能说太细,但是10f兄说不够透彻 那么就在说一点吧:[command|findstr .] 通过管道最后一次传送过去的字符大于或者等于2才可以正常输出 为什么? 还是那句话没有官方支持只有自己去理解,仔细想一下9f应该可以找到答案


2010-5-2 15:32
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
qzwqzw
银牌会员

天的白色影子


积分 2343
发帖 636
注册 2004-3-6
状态 离线
『第 13 楼』:  

正在写回复 老兄有空的话再多等等 ('command')中的代码会进行2次预处理 这我是明白的 我只是说二次预处理一般不这样用而已 所以我说你的示例与我的第一个例子差别不大 也就是说我们一般用三对百分号的形式%%%varname%%% 而不太常用两对百分号的形式%%var%% 关于find与findstr的区别 大概你没有太明确的结论 “通过管道最后一次传送过去的字符大于或者等于2才可以正常输出” 这只是一种针对findstr的近似情况 但是你9楼提供的示例一并不能佐证这个观点 因为那个例子是需要两个回车而不是两个以上的字符 所以这个问题需要再讨论再明确 关于9楼第6节 我只是说set的输出 而不是findstr的输出 这是我书写的疏漏 且不去管他 说一句题外话 有些人很喜欢findstr 能用findstr时绝不用find 我恰好相反 能用find时绝不用findstr 从DOS一路赶来 更加相信find的可靠性 而findstr已暴露的种种问题令人担忧 这体现一个很普遍的原理 “越复杂的越脆弱” 功能越多出错的可能性就越大 正如人类自诩比生灵之长 真要遇到自然灾害 未必会比蚂蚁老鼠更晚灭绝 [ Last edited by qzwqzw on 2010-5-2 at 17:00 ]


2010-5-2 16:41
查看资料  发短消息 网志   编辑帖子  回复  引用回复
q8249014
初级用户





积分 175
发帖 45
注册 2007-8-4
状态 离线
『第 14 楼』:  

占位 还得考虑一下 过些时间在回吧 我觉得是findstr接收问题 已经想到一种原因但无法证明,最近实在没时间,过段时间回复大家在讨论下 [ Last edited by q8249014 on 2010-5-4 at 16:18 ]


2010-5-2 17:02
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
basswood
初级用户




积分 113
发帖 8
注册 2003-12-2
状态 离线
『第 15 楼』:  

现在已很少用这个了,纯支持一下...


2010-5-25 11:15
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复

请注意:您目前尚未注册或登录,请您注册登录以使用论坛的各项功能,例如发表和回复帖子等。


可打印版本 | 推荐给朋友 | 订阅主题 | 收藏主题



论坛跳转: