『楼 主』:
[原创]批处理学习帖③
批处理学习帖③ —— 开启延迟环境变量扩展后对转义字符“^”的处理及“文本阅读器”实例讲解
因为“文本阅读器”这段代码中包含众多批处理技巧,所以单独拿出来给同学们讲解。
下面先给同学们解读一下“文本阅读器”
正文开始
“原创文章,转帖请注明出处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 |
|
|