标题: [文本处理] [已解决]批处理启用变量延迟扩展为何不能认识变量? [打印本页]
作者: summerflower 时间: 2010-2-2 13:39 标题: [已解决]批处理启用变量延迟扩展为何不能认识变量?
我写了一段代码,启用了变量延迟的
在我的代码段中有preCopies这个变量set /p preCopies=请输入:
然后我在其他地方取得它的值,我是这样写的echo !preCopies!
照道理应该输出preCopies这个变量中的值,而实际上输出的却是"!preCopies!"(输出不包括引号)
怎么会这样呢
[ 本帖最后由 summerflower 于 2010-3-1 18:51 编辑 ]
作者: tianya520feng 时间: 2010-2-2 14:16
如果是在 "set /p preCopies=请输入:" 这行之后跟 "echo !preCopies!" 语句,肯定是不存在问题的。我遇到过类似的问题,我的问题出在 "echo !preCopies!" 是在另一个语句中调用的,因为变量有它的作用范围(这里应该相当于局部变量),我调用这个变量的时候,其实已经超出了它的作用范围,所以,它当然会输出 "!preCopies!"(输出不包括引号)
不知道你的情况是否也是这样,希望对你有帮助,如果不能解决,建议把代码贴出来,以便于大家帮忙发现问题。
作者: yslyxqysl 时间: 2010-2-2 15:24
在@echo off后面写一行
setlocal enabledelayedexpansion
作者: summerflower 时间: 2010-2-2 22:05
楼上的,我启用了变量延迟的
作者: Batcher 时间: 2010-2-2 22:24
能否把完整代码贴到顶楼给大家看看?
作者: Seter 时间: 2010-2-3 16:08
其他地方..你要敢说是两个不同P处理俺要爆发的..
作者: summerflower 时间: 2010-2-3 21:23
代码很长,有300多行,不容易理解
所以有必要把思路说一下
难为各位高手耐心看看了。
如果有不清楚的地方,加Q:954769289,谢谢啦
这是一个备份程序。
贴出来的代码实现备份管理功能:添加、删除备份任务。
可以添加两种类型的备份任务:提示和文件复制。
1. 提示任务可以在某个时间跳出提示信息。比如你希望每个星期都备份金山词霸中的生词表,那么你可以添加一个提示任务,提示信息为:“请备份金山词霸生词表”。
提示任务存在的意义:大部分备份只需要复制文件就可以了,但是有的备份就不是简单的复制,而需要手动操作。
比如金山词霸的生词本,因为我不知道是由哪些文件来存储生词本的,我无法通过直接拷贝相应的文件来备份;每次备份都必须打开金山词霸的生词本,手动导入导出。
提示任务可以在某个时间提示你要做哪些备份工作,以免忘记这些需要手动进行的操作。
2. 文件复制。这就是绝大部分备份要做的工作了。它在某个时间将你指定的源文件或文件夹拷贝到目标文件夹。
你可以指定要保留的备份数目,比如书签,每天都备份,保留3份。那么在第4天进行备份的时候,除了把文件和文件夹拷贝到目标目录外,还会删除第1天的备份。
还可以指定执行备份前要执行的程序,比如某个你想备份的文件夹中会产生许多临时文件,在备份前你想清理一下文件,就可以设定它。
你可以对这些任务设定的频率为:每天、每个星期、每个月、每3个月、每6个月。
配置文件:
分成两种,主配置文件和副配置文件。
1. 主配置文件是ini,它由若干行构成,每一行是一条记录,行又由若干字段构成,字段之间用Tab键隔开。借用的数据库的概念哈。
如果是提示任务,有这些字段:任务名称、要执行的动作(对于提示任务来说,它的值就是“提示任务”),提示信息,执行频率。
如果是复制任务,有这些字段:任务名称、要执行的动作(对于复制任务来说,它的值就是“文件复制”),要保留的份数,在备份前要执行的程序。
对于每条记录还有一个隐含的字段:就是ID号。每一条记录的ID号就是它行号,它可以唯一的标志一条记录。
2. 副配置文件。
如果是文件复制型备份任务,那么它会有一个以频率+ID号的文件和它对应。
比如我添加了任务“备份chrome设置”,每个星期执行,它在ini中处于第3行,那么与它相对应的副配置文件的文件名为“每个星期3”
在副配置文件中,第一行是要拷贝到的目标文件夹,以后的行都是源文件或文件夹。
配置文件的一个例子:
ini
金山词霸生词本备份 提示任务 请备份生词本 每个星期
firefox设置备份 文件复制 3 每个月
每个月2
D:\mydocument\My Dropbox\firefox设置备份
c:\Documents and Settings\Administrator\Application Data\Mozilla\Firefox\Profiles\
运行的时候,要选择添加新备份任务→添加复制任务,才会运行到出错的地方。
在第125行定义preCopies,在126行到154行之间使用到这个变量
[ 本帖最后由 summerflower 于 2010-2-3 21:33 编辑 ]
作者: summerflower 时间: 2010-2-3 21:23
- @echo off
- setlocal
- setlocal enabledeayedexpansion
- title 设置备份任务
- echo ┏┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┓
- echo ┊ 对备份任务进行设置 ┊
- echo ┊author summerflower ┊
- echo ┊contact summerflower.zxm@google.com ┊
- echo ┊version 1.0 ┊
- echo ┊release 2010-02 ┊
- echo ┊ ┊
- echo ┊程序限制:至多可以处理999个任务 ┊
- echo ┗┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┛
- echo.
- set "freq=每天 每个星期 每个月 每3个月 每6个月"
- :inputmenu1
- echo ┌────────────────────┐
- echo │主菜单 │
- echo ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┤
- echo │ 1.添加新备份任务 │
- echo │ 2.删除备份任务 │
- echo └────────────────────┘
- set /p menu1=请输入你要进行的操作:
- if %menu1%==1 goto menu1_o1
- if %menu1%==2 goto menu1_o2
- echo 你的输入有误,请输入正确的选项
- goto inputmenu1
- rem menu1_o1开始。1.添加新备份任务
- :menu1_o1
- :inputmenu1_1
- echo ┌────────────────────┐
- echo │ 添加备份任务,请选择你要添加的任务类型 │
- echo ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┤
- echo │ 1.添加提示任务 │
- echo │ 2.添加复制任务 │
- echo └────────────────────┘
- set /p menu1_1=请输入你要进行的操作:
- if %menu1_1%==1 goto menu1_1_o1
- if %menu1_1%==2 goto menu1_1_o2
- echo 你的输入有误,请输入正确的选项
- goto inputmenu1_1
- rem menu1_1_o1开始。1.添加新备份任务→1.添加提示任务
- :menu1_1_o1
- echo 添加提示任务
- :inputname1
- set /p name=请输入名称:
- if not defined name (
- echo 名称不能为空
- goto inputname1
- )
- :inputMessage
- set /p message=请输入提示信息:
- if not defined message (
- echo 提示信息不能为空
- goto inputMessage
- )
- :inputmenu1_1_1
- echo ┌────────────────────┐
- echo │请输入你要提示的频率 │
- echo ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┤
- echo │ 1.每天 │
- echo │ 2.每个星期 │
- echo │ 3.每个月 │
- echo │ 4.每3个月 │
- echo │ 5.每6个月 │
- echo └────────────────────┘
- set /p menu1_1_1=请输入你要提示的频率:
- if %menu1_1_1%==1 (
- echo %name% 提示备份 %message% 每天>ini
- goto menu1_1_1end
- )
- if %menu1_1_1%==2 (
- echo %name% 提示备份 %message% 每个星期>>ini
- goto menu1_1_1end
- )
- if %menu1_1_1%==3 (
- echo %name% 提示备份 %message% 每个月>>ini
- goto menu1_1_1end
- )
- if %menu1_1_1%==4 (
- echo %name% 提示备份 %message% 每3个月>>ini
- goto menu1_1_1end
- )
- if %menu1_1_1%==5 (
- echo %name% 提示备份 %message% 每6个月>>ini
- goto menu1_1_1end
- )
- echo 你的输入有误,请输入正确选项
- goto inputmenu1_1_1
- :menu1_1_1end
- rem menu1_1_o1结束。1.添加新备份任务→1.添加提示任务
- goto menu1_1end
- rem menu1_1_o2开始。1.添加新备份任务→2.添加复制任务
- :menu1_1_o2
- echo ==========添加复制任务==========
- :inputname2
- set /p name=请输入名称:
- if not defined name (
- echo 名称不能为空
- goto inputname2
- )
- rem 把所有的文件和文件夹放入环境变量src中,以分号隔开。
- set src=
- :loopDrag
- set /p srctmp=请拖入源文件或文件夹:
- set srctmp=%srctmp:"=%
- if defined src (
- set src=%src%;%srctmp%
- ) else (
- set src=%srctmp%
- )
- rem 如果继续拖入选y,则跳到输入源文件或文件夹处,输入下一个源文件或文件夹
- set /p optConDrag=是否继续拖入?[y/n]
- if %optConDrag%==y goto loopDrag
- :inputDst
- set /p dst=请输入目标文件夹(必须是绝对路径):
- if defined dst (
- set dst=%dst:"=%
- ) else (
- echo 目标文件夹不能为空
- goto inputDst
- )
- :inputPreCopies
- rem 定义preCopies,它代表要保留的份数
- set /p preCopies=请输入要保留的份数:
- rem 检查preCopies输入是否正确,要求输入应该是一个合法数字。
- rem 循环截取preCopies中的每一个字符,检查它们是否为数字。
- rem 如果为不是数字,则表明输入的要保留的份数格式不正确,要求重新输入。
- rem digFlag用来标识输入是否合法。初始值为true,一旦有字符小于0或大于9,就将它的值设为false,并跳出循环。
- set cnt=0
- set digFlag=true
- :loopPreCopies
- echo 调试信息 用百分号引用结果是正确的 %preCopies%
- echo 调试信息 用感叹号引用不能输出环境变量preCopies的值 !preCopies!
- echo 调试信息 尝试从preCopies中获取一个字符,不能得到正确结果 !preCopies:~%cnt%,1!
- set strtmp=!preCopies:~%cnt%,1!
- if not defined strtmp goto loopPreCopiesEnd
- if %strtmp% lss 0 (
- set digFlag=false
- goto loopPreCopiesEnd
- )
- if %strtmp% gtr 9 (
- set digFlag=false
- goto loopPreCopiesEnd
- )
- set /a cnt+=1
- goto loopPreCopies
- :loopPreCopiesEnd
- if %digFlag%==true (
- set /a preCopies=%preCopies%
- ) else (
- echo 你的输入有误,请重新输入
- goto inputPreCopies
- )
- :inputmenu1_1_2
- echo ┌────────────────────┐
- echo │ 请输入你要备份的频率 │
- echo ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┤
- echo │ 1.每天 │
- echo │ 2.每个星期 │
- echo │ 3.每个月 │
- echo │ 4.每3个月 │
- echo │ 5.每6个月 │
- echo └────────────────────┘
- set /p menu1_1_2=请输入你要备份的频率:
- :inputmenu1_1_2
- if %menu1_1_2%==1 (
- set menu1_1_2freq=每天
- goto menu1_1_2_deal
- )
- if %menu1_1_2%==2 (
- set menu1_1_2freq=每个星期
- goto menu1_1_2_deal
- )
- if %menu1_1_2%==3 (
- set menu1_1_2freq=每个月
- goto menu1_1_2_deal
- )
- if %menu1_1_2%==4 (
- set menu1_1_2freq=每3个月
- goto menu1_1_2_deal
- )
- if %menu1_1_2%==5 (
- set menu1_1_2freq=每6个月
- goto menu1_1_2_deal
- )
- echo 你的输入有误,请输入正确的选项
- goto inputmenu1_1_2
- rem 将设置写入文件
- :menu1_1_2_deal
- set /p preext=请拖入你在此备份之前要执行的程序:
- if defined preext (
- set preext=!preext:"=!
- echo %name% 文件复制 %preCopies% %menu1_1_2freq% !preext!>>ini
- ) else (
- echo %name% 文件复制 %preCopies% %menu1_1_2freq%>>ini
- )
- set linecnt=0
- for /f %%a in (ini) do set /a linecnt+=1
- echo %dst%>>%menu1_1_2freq%%linecnt%
- set cnt=0
- :loopwholestring
- set srctmp=!src:~%cnt%,1!
- if not defined srctmp goto endwholestring
- if "%srctmp%"==";" (
- echo !src:~0,%cnt%!>>%menu1_1_2freq%%linecnt%
- set src=!src:~%cnt%!
- set src=!src:~1!
- set cnt=-1
- )
- set /a cnt+=1
- goto loopwholestring
- :endwholestring
- echo %src%>>%menu1_1_2freq%%linecnt%
- rem menu1_1_o2结束。1.添加新备份任务→2.添加复制任务
- goto menu1_1end
- :menu1_1end
- rem menu1_1结束。1.添加新备份任务
- goto end
- rem menu1_o2开始。2.删除备份任务
- :menu1_o2
- echo 删除备份任务
- if not exist ini (
- echo 没有任何备份任务
- goto end
- )
- for %%a in (ini) do (
- if %%~za==0 (
- echo 没有任何备份任务
- goto end
- )
- )
- set cnt=1
- rem 可以处理至多999个任务
- for /f "tokens=*" %%a in (ini) do (
- set "strtmp=!cnt!. "
- set strtmp=!strtmp:~0,5!
- echo !strtmp!%%a>>tmp
- set /a cnt+=1
- )
- set /a cnt-=1
- set strtmp=00%cnt%
- set strtmp=%strtmp:~-3%
- :inputTaskNO
- more tmp
- set /p taskNO=请选择你要处理的任务号:
- set strtmp2=00%taskNO%
- set strtmp2=%strtmp2:~-3%
- if %strtmp2% lss 001 (
- echo 没有这样的任务号
- goto inputTaskNO
- )
- if %strtmp2% gtr %strtmp% (
- echo 没有这样的任务号
- goto inputTaskNO
- )
- set taskAction=
- set taskFreq=
- set cnt=1
- for /f "tokens=1,2,3,4,5 delims= " %%a in (ini) do (
- if !cnt!==%taskNO% (
- set taskAction=%%b
- set taskFreq=%%d
- echo 备份名称:
- echo %%a
- echo 执行的动作:
- echo %%b
- echo 执行频率:
- echo %%d
- if %%b==提示备份 (
- echo 提示信息:
- echo %%c
- ) else (
- echo 保留几份:
- echo %%c
- )
- if %%b==文件复制 (
- set dst=
- echo 源文件或文件夹:
- for /f "delims=" %%f in (%%d!cnt!) do (
- if defined dst (
- echo %%f
- ) else (
- set dst=%%f
- )
- )
- echo 目标路径:
- echo !dst!
- )
- if %%b==文件复制 (
- if not "%%e"=="" (
- echo 你在备份前要执行的程序:
- echo %%e
- )
- )
- )
- set /a cnt+=1
- )
- del tmp
- set /p delFlag=你是否要删除此备份任务?[y/n]
- if %delFlag%==y (
- set cnt=1
- for /f "tokens=1,2,3,4,5 delims= " %%a in (ini) do (
- if not !cnt!==%taskNO% (
- if "%%e"=="" (
- echo %%a %%b %%c %%d>>tmpini
- ) else (
- echo %%a %%b %%c %%d %%e>>tmpini
- )
- )
- if !cnt!==%taskNO% (
- if %%b==文件复制 (
- del %%d!cnt!
- )
- )
- if !cnt! gtr %taskNO% (
- if %%b==文件复制 (
- set /a newNO=!cnt!-1
- ren %%d!cnt! %%d!newNO!
- )
- )
- set /a cnt+=1
- )
- del ini
- rem 如果要删除的记录为1,且配置文件中只有一条记录时,
- rem tmpini 文件不存在
- rem 如果cnt为2,表示ini中只有一条记录,你选择了删除操作,
- rem 要删除的也必然是第一条记录,
- rem 所以一个条件cnt是否等于2就够了
- if not %cnt%==2 (
- ren tmpini ini
- )
- )
- goto end
- :end
- endlocal
复制代码
作者: summerflower 时间: 2010-2-3 21:31
由于直接拷贝上面对代码,输出菜单会存在一些问题(主要是html中把多个空格缩减成一个空格了哈,所以菜单的格式存在小小的问题),所以提供一个源代码的的文本文件。
把后缀txt改成bat就可以运行了。
作者: summerflower 时间: 2010-2-3 21:54
[attach]2209[/attach]
作者: batman 时间: 2010-2-3 22:26
我这里测试是正确的,代码如下:- @echo off&setlocal enabledelayedexpansion
- set /p preCopies=请输入要保留的份数:
- rem 检查preCopies输入是否正确,要求输入应该是一个合法数字。
- rem 循环截取preCopies中的每一个字符,检查它们是否为数字。
- rem 如果为不是数字,则表明输入的要保留的份数格式不正确,要求重新输入。
- rem digFlag用来标识输入是否合法。初始值为true,一旦有字符小于0或大于9,就将它的值设为false,并跳出循环。
- set cnt=0
- set digFlag=true
- :loopPreCopies
- echo 调试信息 用百分号引用结果是正确的 %preCopies%
- echo 调试信息 用感叹号引用不能输出环境变量preCopies的值 !preCopies!
- echo 调试信息 尝试从preCopies中获取一个字符,不能得到正确结果 !preCopies:~%cnt%,1!
- pause>nul
复制代码
建议楼主去掉第二行的setlocal和最后一行的enlocal,在代码中有点多余了。
作者: batman 时间: 2010-2-3 22:27
晕,楼主第三行的setlocal enabledelayedexpansion写错了!!!
作者: summerflower 时间: 2010-2-3 23:01
我就是觉得奇怪,为什么写的程序最开始运行得好好的,加了几句echo就不能运行了呢。
大概是我在dos下使用gvim写bat的原因,gvim在dos下总出一些莫名其妙的问题.
强烈感谢batman
[ 本帖最后由 summerflower 于 2010-2-3 23:03 编辑 ]
欢迎光临 批处理之家 (http://bbs.bathome.net/) |
Powered by Discuz! 7.2 |