中国DOS联盟论坛

中国DOS联盟

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

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

游客:  注册 | 登录 | 命令行 | 会员 | 搜索 | 上传 | 帮助 »
作者:
标题: [原创]批处理学习帖③ 上一主题 | 下一主题
q8249014
初级用户





积分 175
发帖 45
注册 2007-8-4
状态 离线
『楼 主』:  [原创]批处理学习帖③

批处理学习帖③ —— 开启延迟环境变量扩展后对转义字符“^”的处理及“文本阅读器”实例讲解

因为“文本阅读器”这段代码中包含众多批处理技巧,所以单独拿出来给同学们讲解。

下面先给同学们解读一下“文本阅读器”

正文开始

“原创文章,转帖请注明出处cn-dos&q8249014哦”

一、“文本阅读器”实例讲解
@echo off&cls
:: Code by CN-DOS bjsh & namejm
set "filename="&set "str="&set "query="
set /p filename=请输入文本名[建议您直接将文本拖放到此窗口中]:&cls
if not defined filename %0
set "filename=%filename:"=%"
for /f "delims=" %%i in ('2^>nul findstr /n .* "%filename%"') do (
    set "str=%%i"
    setlocal enabledelayedexpansion
    set "str=!str:*:=!"
    call :start
    endlocal
)
for /l %%i in (1 1 20) do (cd|set/p=)
echo.
set /p "query=按回车键退出,按N键+回车进行下一次演示^_^"
if /i "%query%" equ "N" (%0) else (exit /b)

:start
cd|set/p=
if defined str (
   <nul set /p= !str:~0,1!
   set "str=!str:~1!"
   goto start
)
echo.
goto :eof
由于它的主要原理我们在“批处理学习帖② —— 输出特殊字符的原理详析”中已讲解完毕,所以上面

的代码我们只讲解核心技巧部分。那么就从for那一段开始吧,然后一句一句拿出来分析,因为单讲

十分抽象且不容易表达出作者使用的技巧,故以例子的形式来给同学们讲解,当然也需要同学们有

较好的批处理功底和良好的理解能力。

1.for语句中的('command')部分的命令是获取文本中所有的内容(包含空行)且加上行号,findstr加上/n

参数则是为了能够正确的输出空行,以下代码则说明此问题,同学们比较下
@echo off
rem 这段代码会舍弃空行


for /f "delims=" %%i in ('findstr .* %0') do (echo.%%i)
notepad %0
pause

@echo off
rem 这段代码正常显示空行


for /f "tokens=1* delims=:" %%i in ('findstr /n .* %0') do (echo.%%j)
notepad %0
pause
2.“set "str=%%i"”则是为了方便进行环境变量替换并兼容“!” 原因看 3 中例子

3.“setlocal enabledelayedexpansion”开启延迟变量扩展,兼容显示字符“!”,所以“set "str=%%i"”

必须在延迟变量扩展开启前执行;在输出时使特殊字符逃过“匹配处理”过程以便正常显示
@echo off
rem 兼容显示“!”
for /f "delims=" %%i in ('findstr /n .* %0') do (
    set "str=%%i"
    setlocal enabledelayedexpansion
    set "str=!str:*:=!"
    echo.!str!
    endlocal
)
notepad %0
pause

@echo off
rem 这段代码会丢弃掉“!”
for /f "delims=" %%i in ('findstr /n .* %0') do (
    setlocal enabledelayedexpansion
    set "str=%%i"
    set "str=!str:*:=!"
    echo.!str!
    endlocal
)
notepad %0
pause

@echo off&setlocal enabledelayedexpansion
:: 正常显示特殊字符
set "test=&"
echo.!test!
pause

@echo off
:: 不显示&
set "test=&"
echo.%test%
pause
具体原因可以参考“批处理学习帖①和②” 提示:“!”是在执行“set "str=%%i"”时被舍弃的

4.“set "str=!str:*:=!"”进行环境变量替换,去除行号。这里我给出两段代码大家测试一下就能知道作

者为什么不用for进行处理了,归根结底还是为了能够完整的输出文本内容。使用for会丢弃掉行首的“:”
@echo off
:: 使用for命令来处理,这段代码会丢弃掉行首的“:”
for /f "tokens=1* delims=:" %%i in ('findstr /n .* %0') do (
    echo.%%j
)
notepad %0
pause

@echo off
:: 使用set替换,这段代码则完全还原
for /f "delims=" %%i in ('findstr /n .* %0') do (
    set "str=%%i"
    setlocal enabledelayedexpansion
    set "str=!str:*:=!"
    echo.!str!
    endlocal
)
notepad %0
pause
因为for语句中的('command')部分用的是findstr /n,所以会给每行加上行号,如果文本中的内容是“:test”

那么加上行号后就变为1::test,但是输出时要去除行号,使用代码1则会忽略掉每行开头的冒号,代码2

中使用set进行替换则不会出现问题“set "str=!str:*:=!"”从变量str值的第一个字符开始到“:”第一次出现

的地方都替换为空

5.“call :start”显示函数的调用 简要的提及关键一句 “<nul set /p= !str:~0,1!” 中使用的ASCII字符

是为了能正常显示“"”“=”  ASCII 码为08的符号 可以尝试打开一个文本,然后输入一个字符,按住

alt键不放再按数字键盘上的0和8然后松开alt键,看看有什么效果  下面的过程留给大家当作业

学习帖子④中将会详细的讲解一下“”退格符号的处理过程

6.“endlocal”结束环境变量扩展  解决最大递归层、兼容 “!”,保证含有“!str!”等类似的字符文本的正常

显示。这也就是为什么环境变量延迟扩展必须在“set "str=%%i"”后开启和在for内部的最后一句结束的原因

还是看以下代码
@echo off
:: 错误显示 !能看到我吗?! !!
for /f "delims=" %%i in ('findstr /n .* %0') do (
    set "str=%%i"
    setlocal enabledelayedexpansion
    set "str=!str:*:=!"
    echo.!str!
)
notepad %0
pause

@echo off
:: 正常显示 !能看到我吗?! !!
for /f "delims=" %%i in ('findstr /n .* %0') do (
    set "str=%%i"
    setlocal enabledelayedexpansion
    set "str=!str:*:=!"
    echo.!str!
    endlocal
)
notepad %0
pause
以上核心技巧部分全部以例子的形式给大家讲出,因为单独来说实在抽象哟,不如例子来的直接,最重要的

还是请同学们仔细阅读实践例中的代码。这就要考察同学们的自学能力喽


“原创文章,转帖请注明出处cn-dos&q8249014哦”


二、开启延迟环境变量扩展后对转义字符“^”的处理 (简介)

开启延迟环境变量扩展后为了能够正常的输出字符“!”,命令解释器会处理转义字符

下面一起来看看转义字符和使用“!”引用的变量之间的关系

开启延迟环境变量扩展后 使用“!”引用的变量和转义字符“^”将同时进行处理

先来看几个例子,然后我们在来揭示其中的规则
@echo off
:: 执行后成功显示test
set "var^=test"
setlocal enabledelayedexpansion
echo !var^^!
pause
1.读取完“echo !var^^!”,进行预处理后代码变为“echo !var^!”
2.直接将“!var^!”扩展为test
@echo off
:: 执行后显示!var!
set "var^=test"
setlocal enabledelayedexpansion
echo ^^!var^^!
pause
1.读取完“echo ^^!var^^!”,进行预处理后代码变为“echo ^!var^!”
2.两个“!”均被转义,结果变为“!var!”
@echo off
:: 执行后显示为 “ test”
set "var^=test"
setlocal enabledelayedexpansion
echo ^^ !var^^!
pause
1.读取完“echo ^^ !var^^!”,进行预处理后代码变为“echo ^ !var^!”
2.第一个“^”被遗弃,“!var^!”扩展为“test”,结果为“ test”
@echo off
:: 执行后显示为 “^test”
set "var^=test"
setlocal enabledelayedexpansion
echo ^^^^!var^^!
pause
1.读取完“echo ^^^^!var^^!”,进行预处理后代码变为“echo ^^!var^!”
2.前两个“^^”经转义后变为一个,“!var^!”扩展为“test”,结果为“^test”

________________________________________________
下面总结一下规则:
  1.变量扩展和转义字符将同时进行处理 (遵循从左向右的原则)
  2.去除多余的“!”
________________________________________________

“原创文章,转帖请注明出处cn-dos&q8249014哦”


三、总结

“文本阅读器”中最大的亮点就是它对特殊字符的处理

在开启延迟环境变量扩展后,CMD为了能够让字符“!”正常输出所以在扩展使用“!”引用的变量时会

处理转义字符“^”,这个有点类似于学习帖①中所讲的命令解释器对“%”的处理

一切的一切都和命令行的预处理机制有关

还是那句话

“特殊字符”在进行“匹配处理”后它才“特殊”,如果缺少这个步骤它就是普通字符

  如果某同学立即举手说我用转义啊“^”,(*^__^*) 嘻嘻……  无所不可哟

由于有前两课的基础,所以这节课的的叙述都比较简洁,所以就只有一点总结的,就是请同学们认真实践以

上所有代码并结合分析过程,争取完全弄明白

①②③这3篇帖子算是一个系列帖,主要讲解特殊字符输出的一些技巧,但是其中又牵扯到了变量扩展、延

迟变量扩展和预处理的一些知识,所以同学们阅读时候有更用心一些。

这一篇可能是这一系列学习帖的最后一帖了,相信同学们看完这三篇帖子一定会对cmd的变量扩展、变量延

迟、特殊字符输出原理和预处理过程有一个新的认识,这也就达到了我写这几篇帖的目的,好,不多说了,

感谢同学们阅读这三篇帖子。祝同学们能天天开心哟o(∩_∩)o

这一系列帖到此全完~~!


如果文中有什么不妥之处,敬请坛友们斧正哦

“原创文章,转帖请注明出处cn-dos&q8249014哦”

2009年12月1日 修订

[ Last edited by q8249014 on 2009-12-3 at 19:30 ]

   此帖被 +27 点积分      点击查看详情   
评分人:【 HAT 分数: +12  时间:2009-10-17 11:01
评分人:【 moniuming 分数: +15  时间:2009-10-19 17:16


2009-10-17 10:53
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
cutebe
新手上路





积分 10
发帖 4
注册 2009-5-14
状态 离线
『第 2 楼』:  

文本阅读器 可改一小段
type "%filename%"|findstr /n .*
以增加对UNICODE编码格式文本(如注册表导出文件)的支持

2009-10-17 13:42
查看资料  发短消息 网志   编辑帖子  回复  引用回复
q8249014
初级用户





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

嗯 可以的 以前原作者他们也讨论过这个问题

利用type命令能正常显示UNICODE编码的特性

但是有利必有弊  即:不能查看加密的批处理啦 呵呵

可以用附件中的代码测试

[ Last edited by q8249014 on 2009-10-18 at 19:41 ]

附件 1: test.rar (2009-10-18 19:41, 94 bytes,下载次数: 7)
2009-10-17 19:59
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
lisyofun
初级用户





积分 87
发帖 61
注册 2008-9-18
状态 离线
『第 4 楼』:  

不错的教程,要好好学习。。。谢谢LZ

2009-10-18 16:37
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
RuiIsRui
新手上路




积分 14
发帖 13
注册 2009-7-6
状态 离线
『第 5 楼』:  

呵呵~多谢楼主,学习学习。



天行健  君子以自强不息
2009-10-23 22:13
查看资料  发短消息 网志   编辑帖子  回复  引用回复

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


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



论坛跳转: