中国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
状态 离线
『楼 主』:  [原创]批处理学习帖② —— 输出特殊字符的原理详析

批处理学习帖② —— 输出特殊字符的原理详析

前言:

我们要输出特殊字符一般都是在特殊字符前面加上“^”对其进行转义,如果只是少量的一两个特殊字

符还可以接受,如果是10个100个呢?那么有没有其他更好的方法进行输出呢?答案是肯定的,下面就

结合实例一起来学习一下特殊字符输出的特殊方法。


在开始之前请新同学先阅读一下 批处理学习帖①中的 [开启延迟环境变量后使用“!”引用的变量的“替换步骤”]

这样有助于代码2的理解

下文中所说的“匹配处理”即预处理工作中对字符进行匹配解释的一个过程 也就是批处理学习帖①中归纳的预

处理工作中的第二个步骤

一、理论讲解

批处理是怎样处理特殊字符的呢? 代码1执行后会显示“test”。
@echo off
:: 代码1
set "var=test&"
echo.%var%
pause
请你先执行一下代码1

分析:

当cmd读取完“echo.%var%”以后,首先会将“%var%”替换为变量的值(即:test&),然后在对“test&”进行

“匹配处理”,这里它会将“&”匹配为命令连接符,下面就是执行代码了(即:echo.test),因为&后面什么命

令也没有所以只会显示“test”。


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


2.代码2和代码1基本相似,只是代码2开启了延迟环境变量扩展,执行结果可大不一样哦。代码执行后会显示“test&”
@echo off&setlocal enabledelayedexpansion
:: 代码2
set "var=test&"
echo.!var!
pause
请你先执行一下代码2

代码2中没有对“&”进行转义处理,为什么能正常输出呢?

分析:

因为代码2中开启了延迟环境变量扩展且变量“var”是使用“!”引用的,所以当读取完“echo.!var!”以后,

“var”不会立即被扩展,而是先进行“匹配处理”工作,然后在执行“echo.!var!”前的最后一步在进行扩

展,在这个时候预处理工作中的“匹配处理”已经进行完毕了,因此就直接将“var”扩展为“test&”,紧

接着执行代码 (即:echo.test&),正是因为没有进行“匹配处理”,所以“&”才得以保留,所以执行完毕

后才会显示“test&”。


代码1和代码2的主要区别在于,代码1中的变量在“匹配处理”前就已经扩展了,所以代码1中的“&”

在“匹配处理”时被命令解释器解释为命令连接符,所以提交给命令主体时就不存在了;代码2中的

变量在“匹配处理”后才进行扩展,所以代码2中的“&”未被命令解释器解释,故得以保留。


以上两个例子仅是为了说明“特殊字符”在进行“匹配处理”后它才“特殊”,如果缺少这个步骤它就是普通字

符,和 1 2 3 4 5 没有什么区别,所以代码2才开启了延迟变量扩展,以使“特殊字符”逃过“匹配处理”过程。

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


二、实例演示

有了上面的理论基础,下面我们就引用两个实例来看一看
@echo off&cls
:: 代码3
:: 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
代码3是 bjsh & namejm 两位版主及其他坛友 经过讨论得出的代码

我仅了做简单的“修整” 现取名为“文本阅读器” o(∩_∩)o...

就这么一段代码包含众多批处理技巧

限于篇幅我就不详细分析了,只简要提及一些,学习帖③会单独进行详细讲解

  1.输出特殊字符的原理 [上段已详述]

  2.“findstr /n” “set "str=!str:*:=!"”[保证输出的完整性。可以正常输出空行]

  3.“set "str=%%i"”[代码必须在开启延迟环境变量扩展之前执行,为了兼容显示字符“!”]

  4.延迟环境变量扩展开启和关闭的地方 [最大递归层解决,字符“!”的显示问题]

  5.“set /p” 显示字符的巧妙运用 [解决换行问题]

  6.ASCII字符的巧妙运用 [兼容显示引号和等号]

代码3还可以查看加密的批处理哦 [非变量截取加密]  还有很多用处大家自己发觉吧

“原创文章,转帖请注明出处cn-dos&q8249014哦”
@echo off&setlocal enabledelayedexpansion
:: 代码4
set "all================================================================================="
for /l %%i in (0 1 80) do (
    cls
    echo.                             loading windows2000...
    echo.!var!!all!
    set "all=!all:~1!"
    set "var=!var!>"
    cd|set/p=
)
pause
代码4是我自己仿写“搞笑开机”中的一段代码,有了上面的讲解这里应该不难理解 我就不详述了

注:因为代码3新同学自行分析可能比较困难,代码4相对较简单一些,所以还是请同学们试分析一下代码4


三、总结

    下面总结一下输出特殊字符的几种常用方法:(下面还是会给出几个例子)
    ___________________________________________
      1.开启延迟环境变量扩展法
      2.使用引号对特殊字符进行引用 (<nul set /p"=&<>")
      3.对特殊字符进行转义处理 “^”
    ___________________________________________

    这里给同学们总结一下开启了变量延迟扩展后和没有开启变量延迟扩展时命令解释器对命令语句处理的步骤

    1.没有开启变量延迟扩展
      (1)读取完命令语句后,cmd会检查使用“%”引用的变量是否被定义,是则扩展为其值,否则用空串替换
      (2)进行预处理匹配工作
      (3)把命令语句提交给命令主体
    2.开启了变量延迟扩展
      (1)读取完命令语句后,cmd不会扩展使用“!”引用的变量
      (2)进行预处理匹配工作
      (3)在命令执行前最后一步对使用“!”引用的变量进行扩展[注意:这里只进行变量扩展,不会再进行匹配处理工作]
         也就是说这个扩展延迟到预处理工作的最后一步了
      (4)把命令语句提交给命令主体

   这里只是简要的总结了一下,同时也是为了让同学们能更好的理解开启延迟变量扩展后特殊字符是怎样逃过“匹配处理”过程的


   所谓的“特殊字符”只有在进行“匹配处理”后它才“特殊”,只要不进行“匹配处理”它就是普通字符啦

   所以同学们要对特殊字符进行输出就要想办法逃过“匹配处理”过程

   技巧:在定义带有特殊字符的变量时可以使用“set "var=&><"”,不加引号“set var=&><”会怎么样?呵呵,

         当然有些同学会立即说转义啊,(*^__^*)


以下几段代码是不启用延迟变量扩展且不使用转义符“^”但能正确输出特殊字符的例子,

但它也有自身的缺陷~~!看看下面几段代码执行结果有什么不同哟

同学们自己分析一下。利用下面的代码还可以写出更好玩的东东哦o(∩_∩)o...

期待大家的作品。
@echo off
set "var==&><"
for /f "tokens=2 delims==" %%i in ('set var') do (echo.%%i)
pause

@echo off
set ".= =&><"
::<nul set /p"=%.%"&pause&exit/b
for /f "tokens=* delims=." %%i in ('set .') do (echo.%%i)
pause

@echo off
echo.                             loading windows2000...
<nul set/p"= =============================================================================="
for /l %%i in (1 1 78) do (<nul set /p=)
for /l %%i in (1 1 78) do (
    <nul set/p"=>"
    cd|set/p=
)
echo.&pause
好这一课到这里就结束了,代码4就算给同学们的作业啦,好好实践并读懂它

这样会令你的批处理水平飞速提高

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

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

2009年12月1日 修订

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

   此帖被 +28 点积分       点击查看详情   
评分人:【 HAT 分数: +12  时间:2009-10-14 20:53
评分人:【 523066680 分数: +15  时间:2009-10-14 20:58
评分人:【 vsbat 分数: +1  时间:2009-12-4 22:03


2009-10-14 17:44
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
HAT
版主





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

set /p后面那个空格和退格讲解的不太详细吧?



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





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

那个嘛 挺简单的  所以就没有详述  呵呵
第三篇我会讲解一下的
版主也可以给大家讲解一下呀

2009-10-17 10:51
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复

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


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



论坛跳转: