标题: [文本处理] [已解决]批处理在启动变量延迟的情况下怎么处理惊叹号? [打印本页]
作者: MantisLin 时间: 2011-2-22 17:32 标题: [已解决]批处理在启动变量延迟的情况下怎么处理惊叹号?
假设一个“recent.m3u”文件(播放列表文件),里面的内容如下:- D:\a\ahaha\abc!.mp3
- D:\a\ohoho\a&bc.mp3
复制代码
(列表中只列出两个特殊的例子,本人真正在弄的是有上千个文件的列表。)
我想把列表中的文件,从“D:\a”复制到“D:\b”,且保留“D:\a”之下的目录结构。
也就是复制成“D:\b\ahaha\abc!.mp3”和“D:\b\ohoho\a&bc.mp3”。
然后由于“ahaha”和“ohoho”文件夹下有一些文件我不想要复制,所以不能用选中“ahaha”和“ohoho”然后复制粘贴的方法……
这样一来就得用批处理了……第一次,我的代码是这样的:- echo off & cls
- setlocal enabledelayedexpansion
- rem ==============================
- rem 变量定义
- set "rsc=D:\a"
- set "rplc=D:\b"
- rem ==============================
- rem 复制m3u播放列表中的文件,并在一定程度上保留其目录结构
- for /f "usebackq tokens=* eol=; delims=" %%a in ("recent.m3u") do (
- set "spth=%%a"
- set "pth=%%a"
- set "pth=!pth:%rsc%=%rplc%!"
- echo.!spth!
- call :MakeFolder "!pth!"
- if not exist "!pth!". (
- if not exist "!pth!". (
- copy /y "!spth!" "!pth!"
- ) else (
- echo.已存在,跳过!
- )
- )
- endlocal
- exit/b
- rem ==============================
- rem 创建目录的、类似于“函数”的存在
- :MakeFolder
- set "pth1=%~dp1"
- if not exist "%pth1%". md "%pth1%"
复制代码
用了上面的代码后发现只要m3u列表中的文件名中含有!、&等特殊符号的时候,这个文件就会复制失败,而其他文件OK!
经过疯狂的尝试,我用一个本人非常不喜欢的做法解决了它。于是代码变成这样……同时问题也解决了……- echo off & cls
- rem ==============================
- rem 变量定义
- set "rsc=D:\a"
- set "rplc=D:\b"
- rem ==============================
- rem 复制m3u播放列表中的文件,并在一定程度上保留其目录结构
- for /f "usebackq tokens=* eol=; delims=" %%a in ("recent.m3u") do (
- set "spth=%%a"
- set "pth=%%a"
- SETLOCAL ENABLEDELAYEDEXPANSION
- set "pth=!pth:%rsc%=%rplc%!"
- echo.!spth!
- call :MakeFolder "!pth!"
- if not exist "!pth!". (
- copy /y "!spth!" "!pth!"
- ) else (
- echo.已存在,跳过!
- )
- ENDLOCAL
- )
- pause
- exit/b
- rem 创建目录的、类似于“函数”的存在
- :MakeFolder
- set "pth1=%~dp1"
- if not exist "%pth1%". md "%pth1%"
- GOTO :EOF
复制代码
问题解决,经过反向推测,问题应该出在for语句一开始给“spth”和“pth”赋值为“%%a”这里。在第一个代码里,这个时候的变量延缓是开着的。所以,MP3文件名中的“!”就被当成是变量的标识符了,所以文件名赋到变量里的时候就已经出错了。
而在第二个代码里,把变量延迟放到赋值后才打开,这样赋到变量里的文件名就没错了……
不过在FOR语句里面不停地SETLOCAL、ENDLOCAL感觉不太爽,哪位大哥有更好的解决办法?
还有那位说把!换成^!的兄台,首先要声明,文件名是从列表中读取的,所以不可能预先把!改成^!,就算要用set来替换也很麻烦。
然后请你试一下,在开启变量延迟的情况下,定义一下变量复制代码
,然后用复制代码
,就像下面的代码,如果你的想法正确的话,结果会是这样:“!a!=我的变量”,但结果不是……- echo off & cls
- setlocal enabledelayedexpansion
- set "a=我是变量"
- echo.^!a^!=!a!
- endlocal
- pause
- exit/b
复制代码
[ 本帖最后由 MantisLin 于 2011-2-24 23:17 编辑 ]
作者: CrLf 时间: 2011-2-22 17:53
方法一:
关闭变量延迟,改用call echo %%变量%%
方法二:
如果非要用变量延迟的话,可以利用预处理,比如:- set 感叹号=!
- setlocal enabledelayedexpansion
- echo !感叹号!
- pause
复制代码
[ 本帖最后由 zm900612 于 2011-2-22 17:54 编辑 ]
作者: MantisLin 时间: 2011-2-22 19:10 标题: 回复 2楼 的帖子
好吧,代码是这样的:
代码的作用在注释中已经有说明,问题就出在当播放列表中,MP3文件名中包含有惊叹号“!”或者“&”等特殊符号的时候,复制会失败。
这个地方貌似也不能用预处理。能否帮我解决一下?
- echo off & cls
- setlocal enabledelayedexpansion
- rem 作用:复制m3u播放列表中的文件并保留一定的目录结构
- rem 说明 所有文件都在"%rsc%"文件夹中,将这些文件复制到"%rplc%"文件夹下
- rem 保留剩下的子文件夹的目录结构
- rem ==============================
- rem 变量定义
- set "rsc=D:\Melody"
- set "rplc=%~dp0recent"
- set "succ=0"
- set "faic=0"
- set "pasc=0"
- rem ==============================
- rem 复制m3u播放列表中的文件,并在一定程度上保留其目录结构
- for /f "usebackq tokens=* eol=; delims=" %%a in ("recent.m3u") do (
- set "spth=%%a"
- set "pth=%%a"
- set "pth=!pth:%rsc%=%rplc%!"
- echo.!spth!
- call :MakeFolder "!pth!"
- if not exist "!pth!". (
- copy /y "!spth!" "!pth!" && (
- set /a "succ=succ+1"
- ) || (
- set /a "faic=faic+1"
- )
- ) else (
- echo.已存在,跳过!
- set /a "pasc=pasc+1"
- )
- )
- rem Log数据打印
- echo.
- echo. 成功数:%succ%
- echo. 失败数:%faic%
- echo. 跳过数:%pasc%
-
- setlocal disabledelayedexpansion
- echo.
- echo. 按任意键退出……
- pause>nul
- exit/b
-
-
- rem 创建目录的、类似于“函数”的存在
- :MakeFolder
- set "pth1=%~dp1"
- if not exist "%pth1%". md "%pth1%"
复制代码
作者: CrLf 时间: 2011-2-22 20:03
大概改了一下,没测试,这样可以避免使用变量扩展:- @echo off & cls
- rem 作用:复制m3u播放列表中的文件并保留一定的目录结构
- rem 说明 所有文件都在"%rsc%"文件夹中,将这些文件复制到"%rplc%"文件夹下
- rem 保留剩下的子文件夹的目录结构
- rem ==============================
- rem 变量定义
- set "rsc=D:\Melody"
- set "rplc=%~dp0recent"
- set "succ=0"
- set "faic=0"
- set "pasc=0"
- rem ==============================
- rem 复制m3u播放列表中的文件,并在一定程度上保留其目录结构
- for /f "usebackq tokens=* eol=; delims=" %%a in ("recent.m3u") do call set %%a
- rem Log数据打印
- echo.
- echo. 成功数:%succ%
- echo. 失败数:%faic%
- echo. 跳过数:%pasc%
-
- echo.
- echo. 按任意键退出……
- pause>nul
- exit/b
-
-
- rem 创建目录的、类似于“函数”的存在
-
- :set
- set "spth=%%a"
- set "pth=%*"
- for %%a in ("%rsc%" "%rplc%") do set "pth=%pth:%%~a=%%~b%"
- echo.%spth%
- set "pth1=%pth%"
- if not exist "%pth1%". md "%pth1%"
- if not exist "%pth%". (
- copy /y "%spth%" "%pth%" && (
- set /a "succ=succ+1"
- ) || (
- set /a "faic=faic+1"
- )
- ) else (
- echo.已存在,跳过!
- set /a "pasc=pasc+1"
- )
复制代码
[ 本帖最后由 zm900612 于 2011-2-22 20:04 编辑 ]
作者: MantisLin 时间: 2011-2-22 21:17 标题: 回复 4楼 的帖子
不行啊,我运行了一下,结果是这样的……- 环境变量 D:\Melody\南拳妈妈\下雨天.mp3 没有定义
- 环境变量 D:\Melody\容祖儿\爱情复兴.mp3 没有定义
- 环境变量 D:\Melody\容祖儿\挥着翅膀的女孩.mp3 没有定义
- 环境变量 D:\Melody\水木年华\一生有你.mp3 没有定义
- 环境变量 D:\Melody\水木年华\在他乡.mp3 没有定义
- 环境变量 D:\Melody\孙悦\哭泣的百合花.mp3 没有定义
- 环境变量 D:\Melody\汤灿\家乡美.mp3 没有定义
- 环境变量 D:\Melody\汤灿\幸福万年长.mp3 没有定义
- 环境变量 D:\Melody\王力宏\大城小爱.mp3 没有定义
- 环境变量 D:\Melody\王力宏\龙的传人.mp3 没有定义
- 环境变量 D:\Melody\王强\秋天不回来.mp3 没有定义
- 环境变量 D:\Melody\王心凌\花的嫁纱.mp3 没有定义
- 环境变量 D:\Melody\王心凌\黄昏晓.mp3 没有定义
- 环境变量 D:\Melody\王心凌\我会好好的.mp3 没有定义
- 环境变量 D:\Melody\仙剑奇侠传\挥剑问情.mp3 没有定义
- 环境变量 D:\Melody\仙剑奇侠传\迴梦游仙·二胡独奏版.mp3 没有定义
- 环境变量 D:\Melody\仙剑奇侠传\仙剑问情.mp3 没有定义
- 环境变量 D:\Melody\仙剑奇侠传\御剑江湖.mp3 没有定义
- 环境变量 D:\Melody\仙剑奇侠传\织梦行云.mp3 没有定义
- 环境变量 D:\Melody\谢雨欣\天仙子.mp3 没有定义
- 环境变量 D:\Melody\徐怀钰\分飞.mp3 没有定义
- 环境变量 D:\Melody\许慧欣\七月七日晴.mp3 没有定义
- 环境变量 D:\Melody\许慧欣\特别来宾.mp3 没有定义
- 环境变量 D:\Melody\许慧欣\我要轻轻为你唱首歌.mp3 没有定义
- 环境变量 D:\Melody\銀魂\days.mp3 没有定义
复制代码
作者: caruko 时间: 2011-2-23 01:08
用^!来处理,表示为!字符,而不会解释成 变量符号。
其实我也是在处理 set /a 的NOT 符号 !时,发现在变量延迟环境下的运行结果天差地别。
试验了很多次,才发现需要带上^。
作者: 随风 时间: 2011-2-23 01:35
建议楼主在顶楼用文字把你的目的描述清楚,代码不但会给别人误导还会让人看得眼晕
作者: wc726842270 时间: 2011-2-23 05:40 标题: 回复 1楼 的帖子
个人认为最好的办法是:将变量放在延迟语句的前面。拿你1L为例(3L的太长了,没心去看)- @echo off
- set "pth=abcabc!.mp3"
- setlocal enabledelayedexpansion
- echo.!pth!
- setlocal disabledelayedexpansion
- pause
- exit/b
复制代码
即可
作者: Batcher 时间: 2011-2-23 12:48 标题: 回复 8楼 的帖子
echo,比echo.效率稍高
作者: wc726842270 时间: 2011-2-23 12:55 标题: 回复 9楼 的帖子
主要是时间上的么?但是echo/比ECHO输出更多的东西,
作者: CrLf 时间: 2011-2-23 15:52
8楼代码没考虑到setlocal最大递归层数,在循环中极易出错。但是直接endlocal又会丢失变量,所以循环中建议这样:- @echo off
- set "pth=abcabc!.mp3"
- setlocal enabledelayedexpansion
- for /f "delims=" %%a in ("!pth!") do (
- endlocal
- echo %%a
- )
- pause
复制代码
[ 本帖最后由 zm900612 于 2011-2-27 23:21 编辑 ]
作者: wc726842270 时间: 2011-2-23 16:02 标题: 回复 11楼 的帖子
确实没有想到,也可以说这方面用的太少了
作者: Batcher 时间: 2011-2-23 17:09 标题: 回复 10楼 的帖子
为什么会输出更多的东西?
作者: liion631818 时间: 2011-2-23 22:32
原帖由 Batcher 于 2011-2-23 12:48 发表
echo,比echo.效率稍高
这样的用法跟预处理是什么关系啊?还看见batman用call,这样的用法
作者: Batcher 时间: 2011-2-24 11:27 标题: 回复 14楼 的帖子
命令分隔符而已,参考:
http://bbs.bathome.net/viewthread.php?tid=4482#pid28940
作者: wc726842270 时间: 2011-2-24 12:41 标题: 回复 13楼 的帖子
主要是怕有时赋值不成功(未知变量),但是加分隔符后不管怎么说也能输出空行。也许是SET后没加引号的原因吧
欢迎光临 批处理之家 (http://www.bathome.net/) |
Powered by Discuz! 7.2 |