中国DOS联盟

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

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

中国DOS联盟论坛
现在时间是 2026-08-12 13:40
中国DOS联盟论坛 » DOS批处理 & 脚本技术(批处理室) » [原创]批处理学习帖③ 查看 1,034 回复 4
楼 主 [原创]批处理学习帖③ 发表于 2009-10-17 10:53 ·  中国 湖北 襄阳 老河口市 电信
初级用户
积分 175
发帖 45
注册 2007-08-04 16:16
19年会员
UID 94640
性别 男
状态 离线
批处理学习帖③ —— 开启延迟环境变量扩展后对转义字符“^”的处理及“文本阅读器”实例讲解

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

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

正文开始

“原创文章,转帖请注明出处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 ]
本帖最近评分记录 (共 2 条) 点击查看详情
评分人分数时间
HAT +12 2009-10-17 11:01
moniuming +15 2009-10-19 17:16
2 发表于 2009-10-17 13:42 ·  中国 福建 三明 电信
新手上路
积分 10
发帖 4
注册 2009-05-14 06:21
17年会员
UID 145071
性别 男
状态 离线
文本阅读器 可改一小段
type "%filename%"|findstr /n .*
以增加对UNICODE编码格式文本(如注册表导出文件)的支持
3 发表于 2009-10-17 19:59 ·  中国 湖北 襄阳 老河口市 电信
初级用户
积分 175
发帖 45
注册 2007-08-04 16:16
19年会员
UID 94640
性别 男
状态 离线
嗯 可以的 以前原作者他们也讨论过这个问题

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

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

可以用附件中的代码测试

[ Last edited by q8249014 on 2009-10-18 at 19:41 ]
附件
test.rar (94 bytes, 下载次数: 7)
4 发表于 2009-10-18 16:37 ·  中国 湖南 郴州 电信
初级用户
★★
积分 87
发帖 61
注册 2008-09-18 11:32
17年会员
UID 125941
性别 男
状态 离线
不错的教程,要好好学习。。。谢谢LZ
5 发表于 2009-10-23 22:13 ·  中国 云南 玉溪 电信
新手上路
积分 14
发帖 13
注册 2009-07-06 12:21
17年会员
UID 148847
性别 女
状态 离线
呵呵~多谢楼主,学习学习。
天行健 君子以自强不息
论坛跳转: