Board logo

标题: [文本处理] [已解决]批处理启用变量延迟扩展为何不能认识变量? [打印本页]

作者: 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

  1. @echo off
  2. setlocal
  3. setlocal enabledeayedexpansion
  4. title 设置备份任务
  5. echo ┏┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┓
  6. echo ┊ 对备份任务进行设置 ┊
  7. echo ┊author summerflower ┊
  8. echo ┊contact summerflower.zxm@google.com ┊
  9. echo ┊version 1.0 ┊
  10. echo ┊release 2010-02 ┊
  11. echo ┊ ┊
  12. echo ┊程序限制:至多可以处理999个任务 ┊
  13. echo ┗┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┛
  14. echo.
  15. set "freq=每天 每个星期 每个月 每3个月 每6个月"
  16. :inputmenu1
  17. echo ┌────────────────────┐
  18. echo │主菜单 │
  19. echo ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┤
  20. echo │ 1.添加新备份任务 │
  21. echo │ 2.删除备份任务 │
  22. echo └────────────────────┘
  23. set /p menu1=请输入你要进行的操作:
  24. if %menu1%==1 goto menu1_o1
  25. if %menu1%==2 goto menu1_o2
  26. echo 你的输入有误,请输入正确的选项
  27. goto inputmenu1
  28. rem menu1_o1开始。1.添加新备份任务
  29. :menu1_o1
  30. :inputmenu1_1
  31. echo ┌────────────────────┐
  32. echo │ 添加备份任务,请选择你要添加的任务类型 │
  33. echo ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┤
  34. echo │ 1.添加提示任务 │
  35. echo │ 2.添加复制任务 │
  36. echo └────────────────────┘
  37. set /p menu1_1=请输入你要进行的操作:
  38. if %menu1_1%==1 goto menu1_1_o1
  39. if %menu1_1%==2 goto menu1_1_o2
  40. echo 你的输入有误,请输入正确的选项
  41. goto inputmenu1_1
  42. rem menu1_1_o1开始。1.添加新备份任务→1.添加提示任务
  43. :menu1_1_o1
  44. echo 添加提示任务
  45. :inputname1
  46. set /p name=请输入名称:
  47. if not defined name (
  48. echo 名称不能为空
  49. goto inputname1
  50. )
  51. :inputMessage
  52. set /p message=请输入提示信息:
  53. if not defined message (
  54. echo 提示信息不能为空
  55. goto inputMessage
  56. )
  57. :inputmenu1_1_1
  58. echo ┌────────────────────┐
  59. echo │请输入你要提示的频率 │
  60. echo ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┤
  61. echo │ 1.每天 │
  62. echo │ 2.每个星期 │
  63. echo │ 3.每个月 │
  64. echo │ 4.每3个月 │
  65. echo │ 5.每6个月 │
  66. echo └────────────────────┘
  67. set /p menu1_1_1=请输入你要提示的频率:
  68. if %menu1_1_1%==1 (
  69. echo %name% 提示备份 %message% 每天>ini
  70. goto menu1_1_1end
  71. )
  72. if %menu1_1_1%==2 (
  73. echo %name% 提示备份 %message% 每个星期>>ini
  74. goto menu1_1_1end
  75. )
  76. if %menu1_1_1%==3 (
  77. echo %name% 提示备份 %message% 每个月>>ini
  78. goto menu1_1_1end
  79. )
  80. if %menu1_1_1%==4 (
  81. echo %name% 提示备份 %message% 每3个月>>ini
  82. goto menu1_1_1end
  83. )
  84. if %menu1_1_1%==5 (
  85. echo %name% 提示备份 %message% 每6个月>>ini
  86. goto menu1_1_1end
  87. )
  88. echo 你的输入有误,请输入正确选项
  89. goto inputmenu1_1_1
  90. :menu1_1_1end
  91. rem menu1_1_o1结束。1.添加新备份任务→1.添加提示任务
  92. goto menu1_1end
  93. rem menu1_1_o2开始。1.添加新备份任务→2.添加复制任务
  94. :menu1_1_o2
  95. echo ==========添加复制任务==========
  96. :inputname2
  97. set /p name=请输入名称:
  98. if not defined name (
  99. echo 名称不能为空
  100. goto inputname2
  101. )
  102. rem 把所有的文件和文件夹放入环境变量src中,以分号隔开。
  103. set src=
  104. :loopDrag
  105. set /p srctmp=请拖入源文件或文件夹:
  106. set srctmp=%srctmp:"=%
  107. if defined src (
  108. set src=%src%;%srctmp%
  109. ) else (
  110. set src=%srctmp%
  111. )
  112. rem 如果继续拖入选y,则跳到输入源文件或文件夹处,输入下一个源文件或文件夹
  113. set /p optConDrag=是否继续拖入?[y/n]
  114. if %optConDrag%==y goto loopDrag
  115. :inputDst
  116. set /p dst=请输入目标文件夹(必须是绝对路径):
  117. if defined dst (
  118. set dst=%dst:"=%
  119. ) else (
  120. echo 目标文件夹不能为空
  121. goto inputDst
  122. )
  123. :inputPreCopies
  124. rem 定义preCopies,它代表要保留的份数
  125. set /p preCopies=请输入要保留的份数:
  126. rem 检查preCopies输入是否正确,要求输入应该是一个合法数字。
  127. rem 循环截取preCopies中的每一个字符,检查它们是否为数字。
  128. rem 如果为不是数字,则表明输入的要保留的份数格式不正确,要求重新输入。
  129. rem digFlag用来标识输入是否合法。初始值为true,一旦有字符小于0或大于9,就将它的值设为false,并跳出循环。
  130. set cnt=0
  131. set digFlag=true
  132. :loopPreCopies
  133. echo 调试信息 用百分号引用结果是正确的 %preCopies%
  134. echo 调试信息 用感叹号引用不能输出环境变量preCopies的值 !preCopies!
  135. echo 调试信息 尝试从preCopies中获取一个字符,不能得到正确结果 !preCopies:~%cnt%,1!
  136. set strtmp=!preCopies:~%cnt%,1!
  137. if not defined strtmp goto loopPreCopiesEnd
  138. if %strtmp% lss 0 (
  139. set digFlag=false
  140. goto loopPreCopiesEnd
  141. )
  142. if %strtmp% gtr 9 (
  143. set digFlag=false
  144. goto loopPreCopiesEnd
  145. )
  146. set /a cnt+=1
  147. goto loopPreCopies
  148. :loopPreCopiesEnd
  149. if %digFlag%==true (
  150. set /a preCopies=%preCopies%
  151. ) else (
  152. echo 你的输入有误,请重新输入
  153. goto inputPreCopies
  154. )
  155. :inputmenu1_1_2
  156. echo ┌────────────────────┐
  157. echo │ 请输入你要备份的频率 │
  158. echo ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┤
  159. echo │ 1.每天 │
  160. echo │ 2.每个星期 │
  161. echo │ 3.每个月 │
  162. echo │ 4.每3个月 │
  163. echo │ 5.每6个月 │
  164. echo └────────────────────┘
  165. set /p menu1_1_2=请输入你要备份的频率:
  166. :inputmenu1_1_2
  167. if %menu1_1_2%==1 (
  168. set menu1_1_2freq=每天
  169. goto menu1_1_2_deal
  170. )
  171. if %menu1_1_2%==2 (
  172. set menu1_1_2freq=每个星期
  173. goto menu1_1_2_deal
  174. )
  175. if %menu1_1_2%==3 (
  176. set menu1_1_2freq=每个月
  177. goto menu1_1_2_deal
  178. )
  179. if %menu1_1_2%==4 (
  180. set menu1_1_2freq=每3个月
  181. goto menu1_1_2_deal
  182. )
  183. if %menu1_1_2%==5 (
  184. set menu1_1_2freq=每6个月
  185. goto menu1_1_2_deal
  186. )
  187. echo 你的输入有误,请输入正确的选项
  188. goto inputmenu1_1_2
  189. rem 将设置写入文件
  190. :menu1_1_2_deal
  191. set /p preext=请拖入你在此备份之前要执行的程序:
  192. if defined preext (
  193. set preext=!preext:"=!
  194. echo %name% 文件复制 %preCopies% %menu1_1_2freq% !preext!>>ini
  195. ) else (
  196. echo %name% 文件复制 %preCopies% %menu1_1_2freq%>>ini
  197. )
  198. set linecnt=0
  199. for /f %%a in (ini) do set /a linecnt+=1
  200. echo %dst%>>%menu1_1_2freq%%linecnt%
  201. set cnt=0
  202. :loopwholestring
  203. set srctmp=!src:~%cnt%,1!
  204. if not defined srctmp goto endwholestring
  205. if "%srctmp%"==";" (
  206. echo !src:~0,%cnt%!>>%menu1_1_2freq%%linecnt%
  207. set src=!src:~%cnt%!
  208. set src=!src:~1!
  209. set cnt=-1
  210. )
  211. set /a cnt+=1
  212. goto loopwholestring
  213. :endwholestring
  214. echo %src%>>%menu1_1_2freq%%linecnt%
  215. rem menu1_1_o2结束。1.添加新备份任务→2.添加复制任务
  216. goto menu1_1end
  217. :menu1_1end
  218. rem menu1_1结束。1.添加新备份任务
  219. goto end
  220. rem menu1_o2开始。2.删除备份任务
  221. :menu1_o2
  222. echo 删除备份任务
  223. if not exist ini (
  224. echo 没有任何备份任务
  225. goto end
  226. )
  227. for %%a in (ini) do (
  228. if %%~za==0 (
  229. echo 没有任何备份任务
  230. goto end
  231. )
  232. )
  233. set cnt=1
  234. rem 可以处理至多999个任务
  235. for /f "tokens=*" %%a in (ini) do (
  236. set "strtmp=!cnt!. "
  237. set strtmp=!strtmp:~0,5!
  238. echo !strtmp!%%a>>tmp
  239. set /a cnt+=1
  240. )
  241. set /a cnt-=1
  242. set strtmp=00%cnt%
  243. set strtmp=%strtmp:~-3%
  244. :inputTaskNO
  245. more tmp
  246. set /p taskNO=请选择你要处理的任务号:
  247. set strtmp2=00%taskNO%
  248. set strtmp2=%strtmp2:~-3%
  249. if %strtmp2% lss 001 (
  250. echo 没有这样的任务号
  251. goto inputTaskNO
  252. )
  253. if %strtmp2% gtr %strtmp% (
  254. echo 没有这样的任务号
  255. goto inputTaskNO
  256. )
  257. set taskAction=
  258. set taskFreq=
  259. set cnt=1
  260. for /f "tokens=1,2,3,4,5 delims= " %%a in (ini) do (
  261. if !cnt!==%taskNO% (
  262. set taskAction=%%b
  263. set taskFreq=%%d
  264. echo 备份名称:
  265. echo %%a
  266. echo 执行的动作:
  267. echo %%b
  268. echo 执行频率:
  269. echo %%d
  270. if %%b==提示备份 (
  271. echo 提示信息:
  272. echo %%c
  273. ) else (
  274. echo 保留几份:
  275. echo %%c
  276. )
  277. if %%b==文件复制 (
  278. set dst=
  279. echo 源文件或文件夹:
  280. for /f "delims=" %%f in (%%d!cnt!) do (
  281. if defined dst (
  282. echo %%f
  283. ) else (
  284. set dst=%%f
  285. )
  286. )
  287. echo 目标路径:
  288. echo !dst!
  289. )
  290. if %%b==文件复制 (
  291. if not "%%e"=="" (
  292. echo 你在备份前要执行的程序:
  293. echo %%e
  294. )
  295. )
  296. )
  297. set /a cnt+=1
  298. )
  299. del tmp
  300. set /p delFlag=你是否要删除此备份任务?[y/n]
  301. if %delFlag%==y (
  302. set cnt=1
  303. for /f "tokens=1,2,3,4,5 delims= " %%a in (ini) do (
  304. if not !cnt!==%taskNO% (
  305. if "%%e"=="" (
  306. echo %%a %%b %%c %%d>>tmpini
  307. ) else (
  308. echo %%a %%b %%c %%d %%e>>tmpini
  309. )
  310. )
  311. if !cnt!==%taskNO% (
  312. if %%b==文件复制 (
  313. del %%d!cnt!
  314. )
  315. )
  316. if !cnt! gtr %taskNO% (
  317. if %%b==文件复制 (
  318. set /a newNO=!cnt!-1
  319. ren %%d!cnt! %%d!newNO!
  320. )
  321. )
  322. set /a cnt+=1
  323. )
  324. del ini
  325. rem 如果要删除的记录为1,且配置文件中只有一条记录时,
  326. rem tmpini 文件不存在
  327. rem 如果cnt为2,表示ini中只有一条记录,你选择了删除操作,
  328. rem 要删除的也必然是第一条记录,
  329. rem 所以一个条件cnt是否等于2就够了
  330. if not %cnt%==2 (
  331. ren tmpini ini
  332. )
  333. )
  334. goto end
  335. :end
  336. 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

我这里测试是正确的,代码如下:
  1. @echo off&setlocal enabledelayedexpansion
  2. set /p preCopies=请输入要保留的份数:
  3. rem 检查preCopies输入是否正确,要求输入应该是一个合法数字。
  4. rem 循环截取preCopies中的每一个字符,检查它们是否为数字。
  5. rem 如果为不是数字,则表明输入的要保留的份数格式不正确,要求重新输入。
  6. rem digFlag用来标识输入是否合法。初始值为true,一旦有字符小于0或大于9,就将它的值设为false,并跳出循环。
  7. set cnt=0
  8. set digFlag=true
  9. :loopPreCopies
  10. echo 调试信息 用百分号引用结果是正确的 %preCopies%
  11. echo 调试信息 用感叹号引用不能输出环境变量preCopies的值 !preCopies!
  12. echo 调试信息 尝试从preCopies中获取一个字符,不能得到正确结果 !preCopies:~%cnt%,1!
  13. 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://www.bathome.net/) Powered by Discuz! 7.2