Board logo

标题: [原创] 批处理中处理特殊字符的几种方法 [打印本页]

作者: namejm    时间: 2008-7-17 23:12     标题: 批处理中处理特殊字符的几种方法

特殊字符的处理一直是困扰新手的一大难题,就算是老手,也不敢保证能对各种场合中的特殊字符应付自如,现在给出处理各种特殊字符的方法,供各位参考。

  何谓特殊字符?一般而言,我们把已经在cmd中赋予了各种功能的符号称为特殊字符,比如>、>>、<、<<、|、||、&、&&、^、%,另外,在处理文件路径的时候,空格也可以算作特殊字符。

  很多人都知道,要正确处理路径中的空格,需要用引号把路径括起来,比如:md "c:\test abc\123"。实际上,只要文件路径中含有特殊字符,则引号对是必须的。

  可能还有些人知道,要输出百分号本身,需要在它之前再添加一个百分号,比如,要显示 %abc% 这个字符串,应该写成 echo %%abc%%。

  但是,当我们要输出>、<、|之类的特殊符号的时候,大多数人就开始绞尽脑汁了。

  首先,我们要请出转义字符^,它能帮我们应付绝大多数的特殊字符。例如,我们要显示>,echo ^>即可;要显示|,echo ^|即可,也就是说,在每个特殊字符前加上转义字符^,就可以对特殊字符进行原样输出了。这次,你会原样输出 aueou>|&a^ueo 之类的字符串了吗?

  但是,转义字符^也不能包打天下:当需要输出的是已知的一串或多行字符串的时候,确实可以在每个特殊字符前添加^来原样输出,可是,如果特殊字符的位置不确定,或是我们需要从某个文本中原样读出一串或多行可能含有特殊字符的未知字符串的时候,我们还能用插入转义符号^的办法吗?这显然是行不通的。

  或许你已经意识到,就算是对含有特殊符号的路径用引号对括起来以保证处理它的时候不至出错,但是,当要用echo语句显示这个路径的时候,引号对还是会显示出来,这个多余的引号对并不是我们需要的,有时候甚至是我们无法容忍的。

  转义字符^无用武之地,引号对也行不通,难道我们就这样彻底绝望了吗?

  这次,该for语句隆重出场了。

  先看示例:
  1. @echo off
  2. for /f "delims=" %%i in (test.txt) do (
  3.     set "str=%%i"
  4.     setlocal enabledelayedexpansion
  5.     echo.!str!
  6.     endlocal
  7. )
  8. pause
复制代码
test.txt内容如下(已经囊括了特殊字符):
aoueoa & aeo"83
aeouoaeA3ua^|!:>
><||a6^$2oueo
%ae!aoue


  在这里,我动用了各种手段以保证特殊字符能够原样显示:
  ① 用 "delims=" 避免取到的字符串从空格处被截断;
  ② 用 set "str=%%i" 这样的引号对写法保证把字符串原样赋予变量 str ;
  ③ 在适当的位置开启变量延迟并在合适的地方终止变量延迟,以保证能原样显示变量 str 的值。在这一点上,很多人,包括很多熟练使用 setlocal enabledelayedexpansion 语句的人,都会忽略一些技术细节,从而不能100%原样显示变量 str 的值:我发现,绝大多数的批处理老鸟,都喜欢在@echo off和for语句之间使用 setlocal enabledelayedexpansion 语句,这是个非常不好的习惯——如果变量的值中含有半角感叹号的话,感叹号将被直接抛弃!正确的做法是:在for语句内部而不是外部开启变量延迟,并在合适的地方用endlocal语句终止延迟——endlocal一定要添加上,这是个好习惯,否则,当 setlocal enabledelayedexpansion 被执行32次之后,将会报错,从而引发后续处理错误。

  当然,就算我动用了这么多手段,也不能保证能处理文本中的所有特殊情况:当行首为分号的时候、当存在空行的时候……

  如果要处理所有的特殊情况,请使用如下代码:
  1. @echo off
  2. cd.>output.txt
  3. for /f "delims=" %%i in ('findstr /n .* test.txt') do (
  4.         set "var=%%i"
  5.         setlocal enabledelayedexpansion
  6.         set var=!var:*:=!
  7.         (echo.!var!)>>output.txt
  8.         endlocal
  9. )
  10. start output.txt
复制代码
详细解释请参考本人以前在CN-DOS发的帖子:[讨论]最大限度原样输出含特殊字符的指定行内容
作者: 基拉freedom    时间: 2008-8-17 16:51

setlocal enabledelayedexpansion插在for中 以前都没试过 恩 谢谢提醒了
作者: nopr    时间: 2009-8-6 17:20

刚开的帖吗。没看太懂,只知道这个要记住
作者: bjjgq    时间: 2009-12-3 17:43

老大,其中有一句没有看明白:
set var=!var:*:=!
为什么要用这么一句呢,是要把其中的“*:”删掉吗?
可是我测试了几次,都没有成功。

[ 本帖最后由 bjjgq 于 2009-12-3 17:46 编辑 ]
作者: wankoilz    时间: 2009-12-3 20:45

findstr /n 处理得到的行格式是 行号:原文
set var=!var:*:=! 的目的是去掉第一个冒号以及前面的行号,以得到原行。
作者: hunancjz    时间: 2011-4-6 21:05

5# wankoilz


学习了,之前研究了很久,都没有这么透彻啊!!!

另外,还有高手这样解决
for /f "delims=" %%i in ('dir /s/b test.txt') do (
        for /f "delims=" %%a in ('type "%%~fi"') do (
                set "foo=%%a"
               call,set foo2=%%foo:1111=2222%%
               call,echo/%%foo2%%>>"%%~fi._"
)
move "%%~fi._" "%%~fi"
)
但是存在很多问题,特点是没有用变量延迟。不知道能否改进一下。
作者: ejzhang    时间: 2011-4-10 13:45

学习了,楼主研究的真是太精深了
作者: 秋风·飞扬    时间: 2012-5-2 13:28

天天学习,好好向上!
作者: wc726842270    时间: 2012-5-31 02:00

现在才发现,这3条总结的很不错,犹其是第3条啊,真是范了不少这样的毛病呢
作者: wkl17    时间: 2014-4-10 04:01

cmd中 %random%和!random! 有何区别?之前在一个bat中看到了,一直不解..
作者: cjiabing    时间: 2014-4-10 10:22

回复 10# wkl17


   变量的表现形式,一般是双引号,如 %var%,如果在变量延迟里面就用双引号,如 !var!
具体搜索变量延迟。
作者: nnszuo    时间: 2014-11-9 20:05

本帖最后由 nnszuo 于 2014-11-9 20:09 编辑

原来还可以这样用啊
作者: ai20110304    时间: 2018-8-29 11:04

很赞   ~\(≧▽≦)/~
作者: tiandyoin    时间: 2023-3-3 00:24

本帖最后由 tiandyoin 于 2023-3-3 00:26 编辑

回复 1# namejm


    %~1 后面带数字不会闪退。
rem %~
rem 后面不带数字,即使注释掉照样闪退。

这个问题我相信无人能解




欢迎光临 批处理之家 (http://bbs.bathome.net/) Powered by Discuz! 7.2