Board logo

标题: 无奈何签名代码略析 [打印本页]

作者: willsort     时间: 2006-1-21 22:37    标题: [原创]无奈何签名代码略析

无奈何签名代码略析



  Quote:
  ☆开始\运行 (WIN+R)☆
%ComSpec% /cset,=何奈无── 。何奈可无是原,事奈无做人奈无&for,/l,%i,in,(22,-1,0)do,@call,set/p= %,:~%i,1%<nul&ping/n 1 127.1>nul

引自 无奈何·中国DOS联盟 论坛签名

      这个签名中的代码应用于 WinNT 系列系统(如WinXP)中,将代码内容复制粘贴到的 “开始-运行” 对话框中,可以看到无奈何兄的签名逐字显示。代码长度只有132B,但其中包含许多批处理编程技巧,有些我也是后来才慢慢注意到的。现在我将这段代码分成节段,将其中使用到的重要技巧略作提示,以飨读者,也请原作者无奈何兄和其他批处理达人批评斧正。

      1、%ComSpec% /c

      使用它的目的在于,在运行对话框中调用 set / for / pause 等“内部命令”,因为它们由 NT 系列操作系统中命令行环境的主体程序—— cmd “内部”所支持,并且只能在 cmd “内部”所使用。cmd 全名为 cmd.exe,位于 %SystemRoot%\system32\ 路径下,由环境变量 %ComSpec% 指示其完整的路径。因为它只能在 NT 系列环境下运行,所以实际上它与 cmd /c 是近似等效的。但是因为 %ComSpec% 中包含了 cmd.exe 所在的路径,因此在 cmd.exe 位置比较特殊或者 %path% 变量缺漏的特殊系统环境中也可以使用。详细内容可以在命令行环境中使用 cmd /? 查阅到。

      因为 “运行” 位于 cmd 之外,所以只能调用具有独立可执行文件的“外部命令”,而 cmd 这个“外部命令”就充当了内部命令的“传声筒”,将一串 “内部命令”当作 cmd 的命令行参数,通过 /c 这一选项开关传递到 cmd 内部,交由 cmd 内部解释执行。在 /c 与其后的附加参数命令串之间,一般会插入空格,以增加代码的可读性;无奈何兄省略空格,正是他提到的“尽量字符最短”和“尽量晦涩难读”要求的体现。而如果在命令行环境中使用,并且用 cmd 代替 %ComSpec% ,则 cmd 与 /c 之间的空格也可省略。这些省略空格的用法,有时并不单纯出于精简代码的目的,而是为了应付某些命令或程序比较羸弱的字符串分析算法——我们有时需要将整个命令行当作一个字符串来处理,而许多命令行程序会将空格作为一个字符串的结束标记,比如 for 命令中的 (set) 部分。当然,这种同时兼容空格与无空格的用法,一方面体现出其兼容并包的灵活特性,另一方面也为许多命令行扩展程序增加了诸多困扰,这就只能说“剑有双刃”了。

      另外, /c 之后也可以使用“外部命令”,比如后面出现的 ping ,当它在 %path% 中找不到时,需要指明其所在路径。

      2、set,=何奈无── 。何奈可无是原,事奈无做人奈无
      
      此节是将要显示的签名串逆序保存到环境变量中。变量名","的使用在这里有多重含义,除了“两个尽量”的原则外,它还作为 set 与其参数的分隔符,这又是命令行灵活性的例证了——既允许变量名使用非字母数字的字符,又允许这个字符做其它解释。与此异曲同工的还有上面提到的 cmd/c 中“/”,以及“=”“;”等许多字符,这我在旧帖中曾有论述,不太好找了,有兴趣的可以自己多用 cmd 加一些特殊字符来尝试。

      签名串逆序的目的自然又是“尽量晦涩难懂”,这与后面 for 中的 (22;-1;0) 相呼应。

      签名串前后的两个特殊字符,就是 ASCII 字符集中的响铃符,其 ASCII 码为07,属于 ASCII 码表中的控制区字符。因控制区字符大多有特殊含义,故使用“记事本”很难输入这个字符,可以使用 DOS 下的编辑器 EDIT,届时先键入 Ctrl+P 开启控制字符显示(即暂时关闭其转义特性),再键入 Ctrl+G (提示:G在字母表中的顺序是7,详细内容请参阅网络上 ASCII 码表的相关信息)即可得到这个字符,当然也可使用 UltraEdit 这类十六进制编辑器,直接键入其 ASCII 代码来输入它。因为 ASCII 控制区字符的显示字形并无统一约定,因此它在命令行环境下看起来像一个圆点,而大多数 Windows 的字体不再能正常显示它。但又因 ASCII 标准被吸收为 Unicode 标准中的一个基本平面,因此支持 Unicode 的 NT 系统仍会正确识别并解释这个在旧 DOS 时代就风靡一时的特殊字符。

      3、&for,/l,%i,in,(22,-1,0)do,

      “&”是命令分隔符,用来分隔一个命令行中的多个命令。Cmd.exe 运行第一个命令,然后运行第二个命令。因为“&”有连接多个命令的功能,所以也称为“命令连接符”。set 是它所连接的第一个命令,for 是第二个命令。需要注意的是,其后的 ping 语句前也存在一个“&”,虽然同是命令分隔符,却分属不同层级,前者分隔 %ComSpec% /c 中的 set 与 for,后者分隔 for 中的 call 与 ping。同类的分隔符还有|,&&,||等,详细内容请查阅Windows帮助“命令提示符”一节。

      以后为 for 的前半节,属于 for 循环的控制部分,实现一个从22到0的逆序循环,替换变量为%i,将在以后的循环体语句块中出现,并被替换为自 22 到 0 这 23 个数字串;详细内容可以在命令行环境中使用 for /? 查阅到。(22,-1,0) 之外的其余逗号都可替换为空格,也可以替换为其它可用的参数分隔符(比如“;”“=”等,注意与命令分隔符的区别),如此使用仍然是“尽量晦涩难懂”的体现。

      4、@call,set/p= %,:~%i,1%<nul

      这是 for 语句块中的第一句代码,目的是根据替换变量 %i 从环境变量 %,% 中取出对应的字符,结合 for 的控制部分,即实现了签名串的逆序逐字显示。@的作用在于禁止其后的 call 语句在命令行中回显,因为 for 语句会创建一个新的命令运行环境来执行循环体中的多条语句,而在这个新环境中命令行回显是开启的。而 call 则实现了命令行转义字符 % 的二次替换:在 for 创建的新环境中依次替换 %i 为 22 到 0 这 23 个数字,在 call 再次创建的新环境中依次再替换 %,:~22,1% 至 %,:~0,1% 为签名串中的每个字符。

      至于命令行如何分析出现的多个转义字符 % 及其所夹杂的替换变量、环境变量和命令行参数,这主要取决于“左侧优先于右侧”、“可替换优先于无可替换”这两个原则,再加上环境变量的延迟替换特性,请读者慢慢自行体会。

      于是,这一句代码就最终替换为“set/p= (某个签名字符)<nul”,/p 的作用是将签名字符当作询问环境变量值的提示语输出,而这个环境变量是没有名字的,所以将不会有环境变量被保存。至于为何不用 echo 来显示字符,是因为 set/p 不会在显示完字符串后再显示一个换行,这样可以使所有的签名字符显示在一行而非一列上;= 后的空格是可以省略的,它显示在每个字符前,因此会增加字符间距,改进显示效果;<nul 则负责满足 set/p 所等待的输入,< 将 set/p 的输入设备由标准的控制台(CON,通常为键盘+屏幕)重定向为空设备(NUL),虽然它并不是一个实际存在的硬件设备,而只是一个软件意义上的概念,但它会像宇宙中的黑洞一样,“吞噬”所有指向它的输入流和输出流,在这里, set/p 的输入需求也被“吞噬”,因此它不会停下来等待用户的输入了。

      5、&ping/n 1 127.1>nul

      & 在第3节已做解释。ping 是一个用于网络环境的外部命令,用以向指定的 IP 地址发送一个“网际消息控制协议 (ICMP)”回响请求消息,详细内容请参考 Windows 帮助中的 ping 命令一节;这里使用它可以暂停少许时间,以实现逐字显示的效果,当然它的暂停时间比较短暂而且不很固定,建议将 n 后的数字 1 改为 2,这样暂停的时间将大约等于 1 秒,详细内容请参考[1]。>nul 与第 5 节的 <nul 近似,只是此时 NUL 将作为输出设备,“吞噬” ping 命令所产生的所有输出信息。


后序

      这篇文章的初衷,源于 maya0su 兄在[2]中的建议,我准备以无奈何兄的签名为蓝本,修改出一个命令行版的批处理代码,能以较通用的方法逐字显示一段指定的文本。起初以为有签名代码做铺垫,稍做一些修改便应该可以实现,但是随着修改的深入,发现了一些比较麻烦的问题(主要是转义字符的兼容型问题),这才着手仔细研究签名代码,发现了以往不曾注意到的细节和对一些代码的错误理解[3],这才有了这篇原创文章。

      其实签名代码中最重要的技巧便是转义字符的二次替换,而我当初错误的将之理解为延迟替换,这也是这篇文章出炉的重要原因之一。但是,当我试图详细解释其中机理时,却发现只能深入而不能浅出,很多内容都牵涉到命令行解释的复杂特性,没有官方文档或其它公开资料可以参考和佐证,而我自己的体会难免会有疏漏,为免贻误读者,只好以一句“自行体会”来含糊带过,说来不免惭愧,敬请广大读者谅解!

参考

[1]批处理编程的异类——时钟(Clock)
http://www.cn-dos.net/forum/viewthread.php?tid=8905#pid54227

[2]批处理参数问题一点谈
http://www.cn-dos.net/forum/viewthread.php?tid=17785

[3]关于"set & echo"变量替换的延迟
http://www.cn-dos.net/forum/viewthread.php?tid=18050

[ Last edited by willsort on 2006-1-22 at 11:34 ]
作者: bush     时间: 2006-1-21 23:56
看看,
好像这个是xp的,不能在纯dos下用吧?
作者: 无奈何     时间: 2006-1-22 00:58
谢谢 willsort 兄的抬举
  这篇文章如果我来写的话,万万不能表达的如此清晰详尽。这段代码是我由偶然想法经过多次的尝试性修改最终完成的,最初的代码并不复杂,我有意识的试探着精简字符,其难度也不大。但兄能逆向拆解,可见功力比我高的不是一点半点。

  来论坛的这些日子从兄及其他朋友那里也学到了不少东西。由于最近出差及忙于年终的一些事务有些日子没能上网,终于忙完,明天就要回老家过春节去了,又要度过半个多月没有网络的日子。预祝坛子里的朋友们新春快乐!
作者: willsort     时间: 2006-1-22 10:44
Re bush:

      这段代码确实只能在 NT 系列系统中使用,而且如在签名中提示的一样,仅在 “开始-运行” 对话框中使用。至于它是否能在非 XP 的2K和2K3中使用,未经现场测试不敢妄断。

Re 无奈何:

      这篇文章断断续续花了三天的工夫才最终完稿,有些技巧也是亲自测试后才更有体会的,所以学业高低不能一概而论,兄不必自谦。

      其它回复请见原稿“后序”。下为我编写的通用文本渐次显示的试验代码。存在许多不足,比如不能处理空行,不能正确处理文本行中的转义字符( " % 等)。张贴于下,有心人可以继续研究。
@echo off & setlocal EnableDelayedExpansion
for /f "delims=" %%l in (%1) do (
    set line=%%l
    for /l %%i in (0,1,80) do (
        set /p=!line:~%%i,1!<nul
        ping/n 1 127.1>nul
    )
    echo.
)
pause
[ Last edited by willsort on 2006-1-22 at 14:09 ]
作者: chenall     时间: 2006-3-10 10:44
修改了一下,可以正常显示一些像"="之类的字符,解决了一行只能80个字符的限制
可以达到最多9999个(没有测试过,不知一行是否可以有9999个字符)
一行完就直接跳到下一行,不需要等待
@echo off & setlocal EnableDelayedExpansion
for /f "delims=" %%l in (%1) do (
    set line=%%l
        call :show
    echo.
)
pause
goto end
:show
    for /l %%i in (0,1,9999) do (
        if "!line:~%%i,1!"=="" goto end
        set /p= !line:~%%i,1!<nul
        ping/n 1 127.1>nul
    )

:end

作者: chenall     时间: 2006-3-10 10:48
另外一个版本(有声版,每显示一个字就"嘟"一下)
@echo off & setlocal EnableDelayedExpansion
for /f "delims=" %%l in (%1) do (
    set line=%%l
        call :show
    echo.
)
pause
goto end
:show
    for /l %%i in (0,1,9999) do (
        if "!line:~%%i,1!"=="" goto end
        set /p=!line:~%%i,1!<nul
    )

:end

作者: chenall     时间: 2006-3-10 10:51
由于set /p=!line:~%%i,1!<nul
里面的可以让PC喇叭响一下"嘟"声.并且有延迟效果,所以就不需要使用PING来延迟了.

注:我的系统是2003的,以上程序在我的系统中测试正常.
以上的两个版本均无法正常显示"!","^"和空行
其它的字符均可以(我试了键盘上所有可以按出来的字符).只有"!"和"^"不能显示.

[ Last edited by chenall on 2006-3-10 at 11:19 ]
作者: chenall     时间: 2006-3-10 11:16
经过测试,
终于解决了不能显示"!","^"的问题!
新的代码如下.
现在基本上可以算是完美的了.只差一个无法处理空行的问题了.

稍微解释一下.
可以显示特殊字符主要是这一句
set /p= !line:~%%i,1!<nul
是退格符(删除前一个字符)(ASCII码08)
所以在前面多放了一个空格.如果不加这个空格就会变成显示一个字符就删除一个字符.
另外就是在读取出来的每一行后面加了一个用来判断每一行结束的字符.
@echo off
for /f "delims=" %%l in (%1) do (
    set line=%%l
        call :show
    echo.
)
pause
goto end
:show
setlocal EnableDelayedExpansion
for /l %%i in (0,1,9999) do (
        if "!line:~%%i,1!"=="" goto end
        set /p= !line:~%%i,1!<nul
        ping/n 1 127.1>nul
    )

:end
我用来显示的文件内容
`1234567890-=\
~!@#$%^&*()_+|
qwertyuiop[]
QWERTYUIOP{}
asdfghjkl;'
ASDFGHJKL:"
zxcvbnm,./
ZXCVBNM<>?
""""""""""
!!!!!!!!!!
^^^^^^^^^^
&&&&&&&&&&
[ Last edited by chenall on 2006-3-10 at 11:41 ]
作者: maya0su     时间: 2006-3-21 17:27
原来在这儿,终于找到了,我还以为willsort兄跟无奈何兄没兴趣做这点儿事!经过弟我的测试chenall兄的代码更好一些,在此写过以上各位,willsort兄又给我上了一课,太精彩了,已收藏,谢谢!
作者: doscc     时间: 2006-3-27 22:42
顶顶
作者: IceCrack     时间: 2006-7-29 02:56
哎.没有想到一个签名还能引出来这么大的学问啊.真的不简单
作者: electronixtar     时间: 2006-7-29 14:49
一个签名引起的麻烦
作者: my3439955     时间: 2006-10-19 01:01
8楼的代码好棒
但是“只差一个无法处理空行的问题了”
这不能不说是一个遗憾
小弟略加修改
成一续貂之作
@echo off

type %1 | find "" /V /N | findstr "^\[[0-9]*\]$" >C:\_tmp_.txt
set /A "turn=1"
for /f "usebackq delims=" %%l in (%1) do (
    call :space
    set line=%%l
    if "%line%"=="" (
        echo.
    ) else (
        call :show
    )
    echo.
    set /A "turn+=1"
)
del C:\_tmp_.txt
pause
goto :EOF

:show
setlocal EnableDelayedExpansion
for /l %%i in (0,1,9999) do (
    if "!line:~%%i,1!"=="" goto :EOF
    set /p= !line:~%%i,1!<nul
    ping/n 1 127.1>nul
)
goto :EOF

:space
    :begin
    type C:\_tmp_.txt | find "[%turn%]">nul && (
        echo.
        set /A "turn+=1"
        goto :begin
    )
goto :EOF
借用八楼的测试文件:
`1234567890-=\


~!@#$%^&*()_+|
qwertyuiop[]
QWERTYUIOP{}
asdfghjkl;'
ASDFGHJKL:"
zxcvbnm,./
ZXCVBNM<>?
""""""""""

!!!!!!!!!!
^^^^^^^^^^


&&&&&&&&&&
[ Last edited by my3439955 on 2006-10-19 at 01:14 ]
作者: yfd11     时间: 2006-10-19 10:29
,@call,set/p= %,:~%i,1%<nul
老大这部分不懂啊.为什么加,号.就是%,:~%i,1%为什么不输出变量","的所有内容呢?
作者: NaturalJ0     时间: 2006-10-19 22:12
好复杂,以前就自己看过这段签名,看不懂@_@,今天看了这段分析总算懂了。^_^
作者: lxmxn     时间: 2006-10-20 00:04

  与其说无奈何兄的签名厉害,不如说willsort兄的讲解更精彩…………=_=

作者: jieok3375     时间: 2006-10-20 00:36
学习了……
作者: chenall     时间: 2006-10-26 05:29
经测试13楼的代码,无法正常显示中文.
作者: chenall     时间: 2006-10-26 05:42
13楼的思路不错.
type %1 | find "" /V /N | findstr "^\[[0-9]*\]$" >C:\_tmp_.txt
可以考虑使用.
findstr /n "^$" %1 >C:\_tmp_.txt
再修改一下代码就完美了.
作者: chenall     时间: 2006-10-26 06:10
利用13楼的思路,编写了这个版本.
总算解决了空行的问题.
应该可以算是最终完美版了吧.
@echo off
findstr /n "^$" %1 >~tmp.shw
find ":" ~tmp.shw 1>nul 2>nul||del ~tmp.shw
set /A "turn=1"
for /f "usebackq delims=" %%l in (%1) do (
        if exist ~tmp.shw call :space
        set line=%%l
        call :show
        set /A "turn+=1"
        echo.)
del ~tmp.shw
pause
goto :EOF

:show
setlocal EnableDelayedExpansion
for /l %%i in (0,1,9999) do (
    if "!line:~%%i,1!"=="" goto :EOF
    set /p= !line:~%%i,1!<nul
    ping/n 1 127.1>nul
)
goto :EOF

:space
    findstr "^%turn%:$" ~tmp.shw>nul && (
        echo.
        set /A "turn+=1"
        goto :space
    )
goto :EOF

作者: redtek     时间: 2006-11-6 22:40
这么精彩的又内容欣赏了一遍,哈哈……

[ Last edited by redtek on 2006-11-6 at 10:42 PM ]
作者: yuanzijia08     时间: 2006-11-18 11:05
强,,相当强!!!!!
单膝脆地佩服
作者: yuanzijia08     时间: 2006-11-18 12:17
@echo off & setlocal EnableDelayedExpansion
for /f "delims=" %%l in (%1) do (
    set line=%%l
    for /l %%i in (0,1,80) do (
        set /p=!line:~%%i,1!<nul
        ping/n 1 127.1>nul
    )
    echo.
)
pause


为什么这个代码就不能处理!这样的字符呢   别说因为是特殊字符就不能处理  我希望了解不能处理的内在原因  谢谢
作者: redtek     时间: 2006-11-18 22:59


  Quote:
Originally posted by yuanzijia08 at 2006-11-18 00:17:
@echo off & setlocal EnableDelayedExpansion
for /f "delims=" %%l in (%1) do (
    set line=%%l
    for /l %%i in (0,1,80) do (
为什么这个代码就不能处理!这样的字符呢   别说因为是特殊字符就不能处理  我希望了解不能处理的内在原因  谢谢
...

) 你的23楼的这段代码可以运行~:)
  但需要加参数,因为你 “for /f "delims=" %%l in (%1)” 中指定了%1参数为要读取的文件名,
  所以运行上面批处理时必须指定一个要读取的文件名,例如:

  你23楼的代码文件.BAT   要读取的文本文件名.txt

  按照上面方式运行,就可以把读出的文本文件内容以动画方式显示了~:)


) 你将下面内容存成文本文件,然后用你23楼代码运行并读取这个文件。
我爱北京天安门~:)
我爱伟大的中国~:)
我爱伟大中国所有的pp美眉们~:)~
  把上面内容命令为:   A.TXT

  你的23楼代码.BAT  A.TXT  [回车]

  这样就可以动画显示了~:)


) 23楼代码无法读取含有特殊字符的文本内容,例如:= 这个等号。
  yuanzijia08兄可以先试验上面内容,等没有问题了再考虑写出可以显示特殊特殊号的代码~:)
作者: redtek     时间: 2006-11-18 23:27
另:

) 为什么特殊字符不能处理?

  是因为当试图以 set /p=!line:~%%i,1!<nul 指令显示含有特殊符号(例如=等号)内容时系统会认为错误。

  为什么系统会认为错误?我们可以分解操作来看到错误的原因:
  现在假设 !line:~%%i,1! 取到的一个字符正好是“=”等号,那么就相当于你执行了:

  
  set /p==<nul
  
  这时候系统会提示:
  
  C:\TEMP>set /p==
  命令语法不正确。
  
  上面就是运行结果。

  但如果要显示一个“=”等号以及特殊符号呢?
  
  C:\TEMP>set /p= =<nul
   =
  C:\TEMP>
  
  看上面就可以显示“=”等号了,因为在要显示的“=”等号前面加了个空格的原因~:)

  …………略过n个分析过程…………

  此时候就想一下,如果我前面预先加一个空格,那么再显示文字的时候会怎么样?
  (这个实验请亲自做一下~:)

  …………略过n个分析过程…………

  (实际发现,原来这样达不到要显示的效果,太浪费长度了,哈哈……)
  (怎么办?)
  (再想……)
  (这个时候,会想到,那么怎么才能消掉我多加上的那个空格呢?)
  (这时候就有可能会想起ASCII码特殊控制字符--如何想起来?平时多用,多看这些内容,没看过绝对想不起来)
  (哪些特殊控制字符可以用呢?--如何知道的?全都试过一遍(因为感兴趣就会全试一遍的:)
  (在编程课上或是学C语言的时候也讲过: \n   \t   等特殊控制字符……)
  (回想……)

  (很可能在不断的实验中,突然想起了那个传说中的“退格“字符,那它的ASCII码是多少呢?)

  (在ASCII码表上有)

  (n过过程历过了以后…………会想到,那这个字符“退格”我如何输入它呢?)
  (办法多了,用Debug,用vbs,用edit内的Ctrl+P--等等,这个Ctrl+p如何知道的?)
  (多则n天少则几分钟,试呗,有帮助,或偶然间看到的某个资料上写着这样可以,全是经验总结的过程)

  (然后,下一步怎么办?)
  (退格符可以输入了,可以使用了,如何应用呢?)
  (……经过n步的实验会发现怎么字符全没显示出来,全缩转到一起了?)
  (原来退格又删掉了刚显示的内容……等等……再想……这不就是传说中的动画呢?)

  (经过这些步骤的亲自--一定要亲自全玩过一遍,学会了:
     ASCII码
     特殊控制字符
     显示特殊控制字符
     如何延时
     什么是延时变量
     for的技巧操作
     变量的赋值与如何“分割”与“提取”变量的部分内容
     如何计数
     如何输入特殊控制字符,很有可能连debug的输入特殊字符和简单操作也学会了
     如何读文件…………

     太多了,但这一切光看好看还不行,那只是表面上懂了(这个懂很可以是记忆力在帮你死记住它,而不是透彻)

  yuanzijia08兄自己一个一个试吧,这就是学习和自我了悟的过程~:)
  虽然用五笔字型打字和说话的速度一样,字打多了也累~:D

  
作者: yuanzijia08     时间: 2006-11-19 11:28
非常非常 感谢redtek大哥的解释   解释得这么清楚  真的很谢谢
但我问个问题啊  我在写批处理的时候都是用记事本  像那个响铃符 (就是在CMD下面 输入Ctrl + G 的那个特殊字符)我应该怎么把那符号输入记事本呢
作者: yuanzijia08     时间: 2006-11-19 11:42
@echo off & setlocal EnableDelayedExpansion
for /f "delims=" %%l in (%1) do (
    set line=%%l
    for /l %%i in (0,1,80) do (
        set /p=!line:~%%i,1!<nul
        ping/n 1 127.1>nul
    )
    echo.
)
pause
上面这个代码 能处理像%这样的字符   但不能处理像!这样的字符

但set /p=!<nul 这个在CMD下面是可以显示为 !的  所以在处理!符号的时候 应该不是set /p=的语法问题   感觉应该是变量延迟方面的问题  我想不出 到底是哪个地方的问题   因为我对变量延迟本来就不太清楚   redtek大哥能给解释下吗
作者: redtek     时间: 2006-11-19 23:02
关于27楼不能显示 “!” 符号的问题,它属于延时变量应用上的问题~:)
当上看上面代码,是赋值中含有“!”符号且这个赋值的范围在延时变量开启的范围之内~:)

至于为什么不能处理“!”,做了个延时变量的演示,运行一下就知道啦~:)
@echo %dbg% off
:: 延时变量实验~:)


::  开启延时变量
setlocal EnableDelayedExpansion

    set "myname=abcdefg!!!!redtek"
    echo 普通输出: %myname%
    echo 延时变量: !myname!
    echo 能看到引号里的符号吗?“!!!”
    echo.
    pause
    echo.
    echo.

::  关闭延时变量
setlocal disabledelayedexpansion

    set "myname=abcdefg!!!!redtek"
    echo 普通输出: %myname%
    echo 延时变量: !myname!
    echo 能看到引号里的符号吗?“!!!”
    echo.
    pause
运行完上面关于延时变量的演示,就知道了 setlocal EnableDelayedExpansion 并不是可了随便找一个地方放就行了~:)


看完运行完上面的代码,请再仔细揣摩8楼chenall兄的代码,就会明白他为什么要将 setlocal EnableDelayedExpansion 放到一个适合的位置,而不是随便放到代码的开头~:)
可见chenall兄的代码在处理特殊字符以及延时变量的应用上都有着非常深的功底~:)
然后再重新揣摩版主的签名代码,看上去简单的就一两行,但这里面凝缩着多少精华~:)

[ Last edited by redtek on 2006-11-19 at 10:11 AM ]
作者: redtek     时间: 2006-11-19 23:16
) 回复第26楼:)

  关于如何输入特殊控制字符详见如下贴子的:第12、14、15以及全贴~:)

如何用“\-/”表示一个进度状态?
http://www.cn-dos.net/forum/viewthread.php?tid=24347&fpage=1
作者: ccwan     时间: 2006-11-20 01:52

作者: aqjazz     时间: 2006-11-20 04:03
确实不错~!看来来DOS联盟是来对了!
作者: tao0610     时间: 2006-11-20 06:44


  Quote:
[code]
if "!line:~%%i,1!"=="" goto :EOF
    set /p= !line:~%%i,1!<nul

20楼这个!
振铃的ASCII码怎么输入的?
换行符能不能用ASCII码表示?

[ Last edited by tao0610 on 2006-11-20 at 02:05 PM ]
作者: hxuan999     时间: 2006-11-23 05:52
好贴,顶~~~~
作者: redtek     时间: 2006-11-25 03:08


  Quote:
Originally posted by tao0610 at 2006-11-19 17:44:


20楼这个!
振铃的ASCII码怎么输入的?
换行符能不能用ASCII码表示?

[ Last edited by tao0610 on 2006-11-20 at 02:05 PM ]

振铃的ASCII码:  alt+07  或  CTRL+G 和其它方法都可以输入~:)
C:\TEMP>echo echo 响一声儿~:) ^G >a.bat

C:\TEMP>a

C:\TEMP>echo 响一声儿~:)
响一声儿~:)

作者: anhui8080     时间: 2006-11-25 12:38
一、都是高人;
二、都相``当``谦虚^○^
作者: ciao     时间: 2006-11-28 06:52
都素强人啊!``  我顶
作者: liuxin31554155     时间: 2007-1-19 05:45
真强人 PF一个
作者: liuxin31554155     时间: 2007-1-19 06:06
一个字强 ~
作者: jtyuer     时间: 2007-1-21 09:21
唉……这一点点的代码足以让我琢磨一辈子了!惭愧啊,痴活了三十几年,看了LZ的解释,还是一头雾水。
惭愧,脸红……
作者: qjbm     时间: 2007-2-5 14:27
%ComSpec% /cset,=何奈无── 。何奈可无是原,事奈无做人奈无&for,/l,%i,in,(22,-1,0)do,@call,,|set/p=%,:~%i,1%<nul

最后的输出段使用一个管道符号,还可以缩减7.8个字符.

[ Last edited by qjbm on 2007-2-5 at 01:37 AM ]
作者: 无奈何     时间: 2007-2-5 15:35


  Quote:
%ComSpec% /cset,=何奈无── 。何奈可无是原,事奈无做人奈无&for,/l,%i,in,(22,-1,0)do,@call,,|set/p=%,:~%i,1%<nul

最后的输出段使用一个管道符号,还可以缩减7.8个字符.

[ Last edited by qjbm on 2007-2-5 at 01:37 AM ]

RE qjbm
兄用管道符延时的思路非常好,精简了好多字符,这是非常不错的优化精简,唯一的一点遗憾是不能自定义打字效果的间隔时间。
在兄的启发下再精简几个字符如下:
%ComSpec% /cset,=何奈无── 。何奈可无是原,事奈无做人奈无&for,/l,%i,in,(22,-1,0)do,@cd|set/p= %,:~%i,1%
[ Last edited by 无奈何 on 2007-2-5 at 04:31 PM ]
作者: qjbm     时间: 2007-2-7 09:22
这个
@cd|
更是迷雾重重了,哈哈.
作者: PPdos     时间: 2007-2-7 09:54
cd 大概是最短的了 所以楼主选它
作者: 无奈何     时间: 2007-2-8 04:01
set/p 的原理 willsort 兄已经讲的非常清楚了,
cd| 制造空输出
<nul 制造空输入
提交给 set/p 都是一样的,只是管道命令慢一些,有类似延时的效果。
作者: csx163     时间: 2007-2-10 14:30
我实在不想打搅高人的聊天,但好帖还是要顶滴。。。
作者: 163lom     时间: 2007-2-10 19:04
连别人的签名都拿来分析,你强……
作者: oilio     时间: 2007-2-11 00:03
强啊,正好给我们新手啃一啃啊,希望能从中取一些精华。谢谢解惑。
作者: lovehack2006     时间: 2007-2-15 14:10
到目前为止还是看不明白,不过相信以后应该能明白的。。

收藏先。。。这里的学习气氛好强。。。。以后常来!!
作者: gne3     时间: 2007-2-17 05:10

作者: 6622186     时间: 2007-2-17 13:25    标题: 回复

试了, 很有意思. 不过不太懂, 复制下来,慢慢学, 还是谢了, 又长了见识.
作者: jmz573515     时间: 2007-2-18 05:24
悍~~
作者: 93145820     时间: 2007-2-21 23:56


  Quote:
Originally posted by 无奈何 at 2007-2-7 03:01 PM:
set/p 的原理 willsort 兄已经讲的非常清楚了,
cd| 制造空输出
<nul 制造空输入
提交给 set/p 都是一样的,只是管道命令慢一些,有类似延时的效果。

以前的"call,"我就是一知半解,现在的"call,,|"以及"cd|"我更是晕了,请高手们再给我讲一下好吗?
1.call在这里是什么作用,为什么要用到call?他后面的","是什么意思,我以前以为是空格,可是"call,,"为什么要用两个空格呀
请高手们不吝赐教呀,虽然楼主和无奈何版主都分析了,楼主的意思好像是call创建了一个新环境再次替换变量,无奈何版主的回复是使替换字符的变量生效,这两句我都不太懂
2.cd|制造了一个空输出给set/p,难道以前的"call,"也是这样吗?这什么要给set/p一个空输出?不给不行吗?不给会有什么后果
作者: 93145820     时间: 2007-3-7 12:31
为什么没有人回答我的问题呀,是不是我问的太白痴了....
作者: redtek     时间: 2007-3-7 22:19
因为兄并没有从这个帖子的第1楼到最后一楼所有的可以做的代码全做过一遍:)
兄也没有把能试验的不同的代码的可行性也全做或试过一遍:)


只有全做过一遍才可以“拉带”出更多的尝试、经验和知识点,全做过以后那些Call和兄所提及的问题都可以迎刃而解了~:)
作者: baba7     时间: 2007-3-7 22:46
奇怪

我这边复制上去后无任何效果
作者: 93145820     时间: 2007-3-10 14:09
谢谢redtek兄的回复,正在从头细读,在等大家回复的时间我也想了不少,已经有些懂了。。。。
再次感谢redtek兄
作者: lidw1983     时间: 2007-4-15 07:03
ding
作者: mtiankong     时间: 2007-4-21 01:29
强贴 ~~~加完分再看
作者: mtiankong     时间: 2007-4-22 01:32
无 奈 人 做 无 奈 事,原 是 无 可 奈 何。— — 无 奈 何
==============================================
代码我重新敲了遍,怎么达不到无奈大大那种字与字之间在显示时产生空格的效果呢??????

[ Last edited by mtiankong on 2007-4-21 at 01:38 PM ]
作者: studythedos     时间: 2007-7-4 13:53
分析的真够详细的....
辛苦了..
作者: studythedos     时间: 2007-7-4 13:53
分析的真够详细的....
辛苦了..
作者: rockdong     时间: 2007-8-31 16:47
分析得实在是太精辟了!看完这个帖子真的受益匪浅。
作者: 99king     时间: 2007-10-13 11:24
不错的,我顶了,辛苦晒楼主
作者: kgdetg1127     时间: 2007-10-23 14:06
牛BI啊。。。顶起