无忧启动论坛

标题: DOS有奖问答No6:关于循环命令FOR的使用 [打印本页]

作者: gmy    时间: 2006-1-10 12:46
标题: DOS有奖问答No6:关于循环命令FOR的使用
[这个贴子最后由gmy在 2006/04/13 11:15am 第 2 次编辑]

为使大家深入讨论DOS技术,本版主会经常提出一些有难度的问题,回答正确的给予加威望等形式的奖励,并且原贴加精,以便查阅。
DOS有奖问答No6:关于循环命令FOR的使用

请用FOR命令简化以下批处理,要求用FOR命令,在纯DOS环境。

if exist c:\boot.ini goto c
if exist d:\boot.ini goto d
if exist e:\boot.ini goto e
...
if exist w:\boot.ini goto w

:c
set drv=c:
copy %drv%\boot.ini %drv%\boot.bak
goto end
:d
set drv=d:
copy %drv%\boot.ini %drv%\boot.bak
goto end
:e
set drv=e:
copy %drv%\boot.ini %drv%\boot.bak
goto end
...  
:w
set drv=w:
copy %drv%\boot.ini %drv%\boot.bak
goto end
:end

编程意图:依次查找C到W盘根目录下的BOOT.INI,将首次找到的BOOT.INI复制到同一目录下,重命名为BOOT.BAK,找到后不再查找,结束程序。


[color=#B22222]重要提示:本贴派生出来的其它问题如ATTRIB,No Ready。。请参看 一键GHOST 的相关批处理,已经得到了完美解决!
作者: magictek    时间: 2006-1-10 22:19
标题: DOS有奖问答No6:关于循环命令FOR的使用
[这个贴子最后由magictek在 2006/01/14 09:50pm 第 1 次编辑]

如果不使用批处理,一句话来完成:
For %f In (c d e f g h i j k l m n o p q r s t u v w)Do If Exist %f:\Boot.Ini Copy %f:\Boot.Ini %f:\Boot.Bak
缺点是不能找到以后不再查找,只能从C一直查到W
如果可以用批处理,就比较容易实现一些:
@Echo Off
For %%f in (c d e f g h i j k l m n o p q r s t u v w) Do If Exist %%f:\Boot.Ini Set Drv=%%f
Copy %Drv%:\Boot.Ini %Drv%:\Boot.Bak
不过我在测试的时候发现还是有点点问题,比如说我D盘F盘各有一个Boot.Ini,的确是检测到F盘有以后就备份F盘的了,但是F盘的Boot.Ini这是Copy了,源文件还在,每次都只能检测到F盘就不能到D盘了,如果要在DOS工具中间加入这个语句,我相反觉得第一种方式(即每个盘都找,只要有就都备份)相对还要安全一些
还是和以前一样,我对葛老师的问答积极参与,但是加密帖子,避免妨碍别人思路和积极性,如果我的回答有什么错误,请葛老师斧正
作者: magictek    时间: 2006-1-11 00:34
标题: DOS有奖问答No6:关于循环命令FOR的使用
[这个贴子最后由magictek在 2006/01/14 09:50pm 第 3 次编辑]

自己发现犯了个错误,第二种里面其实我是对%f反复多次赋值,有效的只是最后赋值的那个,第二条不算,重新想过

越想越复杂,本来正在尝试用for %%f in (c d e f) do set drv%%f=%%f:来对每个分区都赋值一个变量再来搜索的,忽然发现其实只要将c至w的次序反过来,便能够找到第一个有Boot.Ini的分区并对%f最终赋值,然后对该变量代表的分区中的文件备份就可以了
@Echo Off
For %%f in (w v u t s r q p o n m l k j i h g f e d c) Do If Exist %%f:\Boot.Ini Set Drv=%%f
Copy %Drv%:\Boot.Ini %Drv%:\Boot.Bak

个人感觉这个题目非常不错的,使用到了DOS里面最为复杂的for以及比较复杂的if,总记得以前哪位前辈说过:如果完全熟悉for的用法,DOS就可以称为精通了,在一些比较经典的题目里面,例如删除QQ目录中的号码文件夹,for还是很好用的,但是至于for的高级应用,别人写的我看得懂,但是要自己写一个很不错得还是觉得缺乏灵感,光就这一点以后还需要向葛老师多多请教
作者: gmy    时间: 2006-1-11 13:57
标题: DOS有奖问答No6:关于循环命令FOR的使用
公布正确答案 (不是100%符合题意,仅供参考)
@echo off
set drv=notfound
for %%i in (c d e f g h i j k l m n o p q r s t u v w) do if exist %%
i:\boot.ini set drv=%%i
if %drv%==notfound goto err
:ok
cls
echo OK! %drv%\boot.ini is found !
goto end
:err
cls
echo Sorry! boot.ini is not found!
goto end
:end
echo
echo
pause
REM 看点:
REM 1.参数传递:i%%传给%%drv,以解决跳出FOR以后i%%失效的问题。
REM 2.DRV的初始值:DRV的值不能为空,否则if %drv%=="" goto err语句运行失败

作者: magictek    时间: 2006-1-11 22:20
标题: DOS有奖问答No6:关于循环命令FOR的使用
drv值不能为空,这一点的确需要注意
作者: xusen    时间: 2006-1-13 16:59
标题: DOS有奖问答No6:关于循环命令FOR的使用
[这个贴子最后由xusen在 2006/01/13 05:00pm 第 1 次编辑]

REM 2.DRV的初始值:DRV的值不能为空,否则if %drv%=="" goto err语句运行失败
空了应该也是可以的
@echo off
for %%a in (c d e f g h i j k l m n o p q r s t u v w) do if exist %%a:\boot.ini set drv=%%a
if %drv%#==# goto end
echo %drv%

:end
作者: xusen    时间: 2006-1-13 17:03
标题: DOS有奖问答No6:关于循环命令FOR的使用
[这个贴子最后由xusen在 2006/01/13 05:17pm 第 1 次编辑]

建议颠倒盘符顺序  因如果有两个区有BOOT.INI则会选择后个
@echo off
for %%a in (w v u t s r q u o n m l k j i h g f e d c) do if exist %%a:\boot.ini set drv=%%a
if %drv%#==# goto 结束
:处理
copy %drv%:\boot.ini %drv%:\boot.bak /y >nul

:结束

作者: gmy    时间: 2006-1-16 08:05
标题: DOS有奖问答No6:关于循环命令FOR的使用
xusen 指出的两点很重要,也很正确,加威望!
作者: 我是神仙    时间: 2006-3-3 10:20
标题: DOS有奖问答No6:关于循环命令FOR的使用
真的不知道大家有没有实际试过,根本不得行
boot.ini是系统文件,隐藏文件,用COPY是拷贝不了的!!!!!!

其实这个批处理只需要下面这一句就足够了:
@for %%X in (e f g h i j k l m n o p q r s t u v w) do @if exist %%X:\boot.ini attrib %%X:\boot.ini -h -s&&copy %%X:\boot.ini %%X:\boot.bak&&attrib %%X:\boot.ini +h +s&&exit /b

当然,这是一个复合语句,愿意的话也可以将它扩展成下面这个样子:
@echo off
for %%X in (c d e f g h i j k l m n o p q r s t u v w) do @(
if exist %%X:\boot.ini (
attrib %%X:\boot.ini -h -s
copy %%X:\boot.ini %%X:\boot.bak
attrib %%X:\boot.ini +h +s
exit /b
)
if %%X==w echo Not found!
)

关键是要修改boot.ini的属性,当然还要改回来。
另外,大家都知道命令之间可以用&&连接,(或||,有点小区别)
还有就是 可以用括号来实现复合语句,和C语言中的大括号{}差不多
最后,批处理有循环但没有跳出循环的类似break continue的语句,
只能用exit /b了。也可以用goto:eof.或者自己在文件最后定义一个
标号end.
作者: xusen    时间: 2006-3-3 15:25
标题: DOS有奖问答No6:关于循环命令FOR的使用
[这个贴子最后由xusen在 2006/03/03 03:33pm 第 2 次编辑]

if 语句后面的"(" 及 &&连接 只能在WINDOWS环境下的批处理脚本上使用,纯DOS环境可能用不了。
作者: 我是神仙    时间: 2006-3-3 18:53
标题: DOS有奖问答No6:关于循环命令FOR的使用
哈哈原来是纯DOS,眼花了,我说嘛,我这个偶而用一下批处理的都觉得简单的问题怎么会有人不会呢

最好是指定一下是DOS4.0还是6.0还是98版还是6.2还是DOS7.1 还是其他什么
DOS,不同版本的区别还是不少

但boot.ini一般为隐藏系统文件,用copy是拷贝不了的,这一点我还是比较肯定的
作者: 我是神仙    时间: 2006-3-3 18:57
标题: DOS有奖问答No6:关于循环命令FOR的使用
if %drv%#==# goto end
这种方法我倒是经常使用,版主居然也不大知道,看来我还是对批处理略有理解嘛
自我奖励一下啦,呵呵
作者: lxl1638    时间: 2006-3-3 19:03
标题: DOS有奖问答No6:关于循环命令FOR的使用
下面引用由我是神仙2006/03/03 06:53pm 发表的内容:
哈哈原来是纯DOS,眼花了,我说嘛,我这个偶而用一下批处理的都觉得简单的问题怎么会有人不会呢
最好是指定一下是DOS4.0还是6.0还是98版还是6.2还是DOS7.1 还是其他什么
DOS,不同版本的区别还是不少
但boot.ini一般 ...
对标准的文本文件,不管它的属性如何,可以用 Type 命令复制,如要复制隐藏系统文件C:\BOOT.INI 为 C:\BOOT.BAK 可以这样:
[color=#8B0000]
TYPE C:\BOOT.INI>C:\BOOT.BAK

作者: magictek    时间: 2006-3-4 00:49
标题: DOS有奖问答No6:关于循环命令FOR的使用
没必要在一个Attrib上面争论这么长时间吧,这个题目的重点是For的使用上面,不是在Attrib上面,在实际应用中,即使忘记使用Attrib了,也是很容易Debug出来的
作者: 我是神仙    时间: 2006-3-5 20:09
标题: DOS有奖问答No6:关于循环命令FOR的使用
呵呵原来没看见这个问题,现在既然看到了还是发表一点个人看法吧

找到后不再查找,结束程序。
GMY的明显不符要求嘛,怎么叫正确答案呢,
建议改成“参考答案”(他看到了xusen的修改,为什么不改呢?)

纯DOS的批处理功能太弱,是戴着锁链跳舞,编一些小程序真的是不简单啊
不过平时用的多的还是在windows中用一些简单的批处理。windows中的DOS一直
在不断的进步,现在应该说功能非常强大了

用type来拷贝隐藏的文本文件,不错

xusen的不错,指出变量drv可以为空,但他好像没像GMY那样给drv赋初值,这是
不大对的。事实上,变量drv一定要有初值,虽然初值可以为空
谁知道drv这个变量在你用之前是否为空呢?编程,即使是批处理,不能太想当然了吧
我一般是用set drv= 来给drv赋一个空的初值
(其实可以用set local,但纯DOS又好像不行)

其实GMY把这个问题要求用FOR来做真的是不大好做,选的方向不对嘛
用纯DOS的FOR不能中断循环,就是说即使C盘中才有boot.ini,它也
要傻傻的执行二十几遍,晕
我觉得这种循环根本不应该用FOR ,应该用if goto等用法来构造循环,
找到了就跳出来,多爽
参考一下:
test.bat
@echo off
if  %1F==F goto usage
:test
if  %1F==F goto notfound
if exist %1:\boot.ini goto found
shift
goto test
:found
type %1:\boot.ini>%1:\boot.bak 2>nul
goto end
:usage
echo  Usage:
echo  test c d e f  (input all disks you want to test)
goto end
:notfound
echo Not found!
goto end
:end

作者: 我是神仙    时间: 2006-3-5 20:11
标题: DOS有奖问答No6:关于循环命令FOR的使用
当然,只要不要求用FOR,是个人都知道可以这样写,哈哈
作者: 我是神仙    时间: 2006-3-5 21:09
标题: DOS有奖问答No6:关于循环命令FOR的使用
刚才看了sidac在另一贴中的提示,可以通过不用call的调用来退出循环,
确实可行。这样此程序也就可以用FOR来写,倒是简洁一些了:
@echo off
echo copy %%1:\boot.ini %%1:\boot.bak>found.bat
for %%a in (c d e f g h i j k l m n o p q r s t u v w) do if exist %%a:\boot.ini found.bat %%a
echo Not found!
作者: 我是神仙    时间: 2006-3-5 21:12
标题: DOS有奖问答No6:关于循环命令FOR的使用
本来也是想用type来拷贝的,不过对于纯DOS中怎么显示特殊字符不是很清楚
我只知道windows中可用 echo ^> 来显示一个大于号,在纯DOS中不知该怎么写
作者: 我是神仙    时间: 2006-3-5 22:41
标题: DOS有奖问答No6:关于循环命令FOR的使用
@echo off
echo exit|command /k prompt type %%1:\boot.ini$g%%1:\boot.bak$_|find ">">found.bat
for %%a in (c d e f g h i j k l m n o p q r s t u v w) do if exist %%a:\boot.ini found.bat %%a
echo Not found!

作者: xusen    时间: 2006-3-6 12:57
标题: DOS有奖问答No6:关于循环命令FOR的使用
用 IF 也可以这样试试:
====================
@echo off
if not %1#==# goto 下一步
set drv=c d e f g h i j k l m n o p q r s t u v w
call %0 %drv%
:下一步
shift
if %0#==# goto 结束
if not exist %0:\boot.ini goto 下一步
type %0:\boot.ini >%0:\boot.bak
:结束
set drv=
作者: 我是神仙    时间: 2006-3-6 13:23
标题: DOS有奖问答No6:关于循环命令FOR的使用

纯DOS调用自身以前没用过,昨天浏览DOS联盟时倒是发现了那儿的版主willsort早就提过这种用法,没来得及改 :)
现在的DOS倒是支持直接调用标号了.

作者: Hit    时间: 2006-3-19 17:09
标题: DOS有奖问答No6:关于循环命令FOR的使用
寫批處理文件是我的職業, 暈吧!
@ECHO OFF
:INIT
SET FILE=%0
IF @%FILE%==@ SET FILE=\AUTOEXEC.BAT
IF NOT @%1==@ GOTO %1
CALL %FILE% MAIN
GOTO END
:MAIN
FOR %%I IN (C D E F G H I J K L M N O P Q R S T U V W X Y Z) DO IF EXIST %%I:\BOOT.INI CALL %FILE% BACK %%I
GOTO END
:BACK
SET DRV=%2:
ATTRIB -R -S -H %DRV%\BOOT.INI
COPY %DRV%\BOOT.INI %DRV%\BOOT.BAK
GOTO END
:END
作者: Climbing    时间: 2006-4-1 22:31
标题: DOS有奖问答No6:关于循环命令FOR的使用
大家写了不少批处理,都没有发现每个批处理都有一个致命的缺陷:
大家都从c-z检测是否存在boot.ini,难道你们不了解,如果一个磁盘如果有问题(例如光驱没盘)而访问时会出现错误提供的情况吗?(Not Ready)。
如何处理呢?
作者: 我是神仙    时间: 2006-4-13 09:44
标题: DOS有奖问答No6:关于循环命令FOR的使用
我试了一下,在windows中只要dir一下就可以了.
检测一下errorlevel即可
在DOS中,如果不加载光驱,那就不存在问题,
如果加载了光驱,光驱的盘符是很好确认的,跳过即可
作者: 虬雨    时间: 2006-4-13 19:33
标题: DOS有奖问答No6:关于循环命令FOR的使用
我怎么觉得好像编程程序运行啊
作者: magictek    时间: 2006-6-2 23:13
顶起来,不错的帖子,论坛改版后就沉下去了
作者: TCLSHX    时间: 2006-6-25 16:32
原帖由 magictek 于 2006-6-2 11:13 PM 发表
顶起来,不错的帖子,论坛改版后就沉下去了


顶一下
作者: yy1    时间: 2006-6-25 23:10
看晕了,多学习~~~
作者: jmm988    时间: 2006-8-19 19:42
对孜孜不倦的精神致敬!好帖!顶起来!
作者: 安情    时间: 2006-8-20 20:35
看不太懂,只懂一些.
作者: 安情    时间: 2006-8-20 20:40
原帖由 xusen 于 2006-1-13 05:03 PM 发表


建议颠倒盘符顺序  因如果有两个区有BOOT.INI则会选择后个
@echo off
for %%a in (w v u t s r q u o n m l k j i h g f e d c) do if exist %%a:\boot.ini set drv=%%a
if %drv%#==# goto 结束 ...





这个应该和楼主的要求一样吧?
作者: 编程者    时间: 2008-3-11 12:15
好帖子,努力学习!!!!
作者: hendy2008    时间: 2008-3-12 00:54
支持!~~希望能说明一下,给新人学习一下哈
作者: 楚天龙    时间: 2008-5-15 22:29
支持搂主,支持搂主.
作者: 2010ytboy250    时间: 2010-12-10 11:10
呵呵,就是每一个盘都要搞!
作者: microcwj    时间: 2010-12-10 21:14
FOR命令的使用方法的确比较多,用到的时候再找找,呵呵。
作者: 2010fengyun    时间: 2010-12-11 15:55
看了所有代码好象都没有把特殊情况考虑在内(比如遇到查找不成功的异常,类似C里的try..catch..),我不太懂批处理,但是我知道一个好的代码一定要把各种可能的情况都包含在内!而不是仅仅为了完成某个任务.
作者: mrwang123    时间: 2010-12-15 09:38
提示: 作者被禁止或删除 内容自动屏蔽




欢迎光临 无忧启动论坛 (http://bbs.c3.wuyou.net/) Powered by Discuz! X3.3