Board logo

标题: [其他] [已解决]批处理复合语句中是否能使用跳转语句? [打印本页]

作者: summerflower    时间: 2010-2-18 16:33     标题: [已解决]批处理复合语句中是否能使用跳转语句?

复合语句中能用跳转语句吗?我发现复合语句中用跳转语句,它就乱跳,不知道跳到哪里去了
请大家看看下面的代码
  1. @echo off
  2. setlocal enabledelayedexpansion
  3. for /l %%a in (1,1,3) do (
  4.         echo 第%%a次
  5.         set str=
  6.         set /p str=请输入:
  7.         if defined str (
  8.                 :loopStr
  9.                 set strChar=!str:~0,1!
  10.                 set str=!str:~1!
  11.                 if defined str (
  12.                         goto loopStr
  13.                 ) else (
  14.                         goto endLoopStr
  15.                 )
  16.                 :endLoopStr
  17.                 echo .>nul
  18.         ) else (
  19.                 echo ============================
  20.         )
  21. )
复制代码
如果我第一次输入abc
那么执行结果应该是不输出任何结果,并进行第2、3次循环

但事实上我输入abc
执行结果中竟然输出了============================,并且停止了循环

[ 本帖最后由 summerflower 于 2010-2-24 18:16 编辑 ]
作者: hfg1977    时间: 2010-2-18 16:41

复合语句有很多种的呀, 都可以使用跳转语句.
但是使用的结果会有差异, 要看是否需要返回等等.

乱跳的情况没遇到过 -.-  你说说你情况 一起学习啦!
作者: Seter    时间: 2010-2-18 21:34

用是肯定能用的,问题在于怎么用..
作者: summerflower    时间: 2010-2-19 10:38

  1. @echo off
  2. setlocal enabledelayedexpansion
  3. for /l %%a in (1,1,3) do (
  4. echo 第%%a次
  5. set str=
  6. set /p str=请输入:
  7. if defined str (
  8. :loopStr
  9. set strChar=!str:~0,1!
  10. set str=!str:~1!
  11. if defined str (
  12. goto loopStr
  13. ) else (
  14. goto endLoopStr
  15. )
  16. :endLoopStr
  17. echo .>nul
  18. ) else (
  19. echo ============================
  20. )
  21. )
复制代码


如果我第一次输入abc
那么执行结果应该是不输出任何结果,并进行第2、3次循环

但事实上我输入abc
执行结果中竟然输出了============================,并且停止了循环


大家看看仔细看看这段程序吧
作者: Seter    时间: 2010-2-19 12:24

for中的goto会直接跳出循环,只能用call的...
作者: Seter    时间: 2010-2-19 12:26

你要做啥  = =?
作者: summerflower    时间: 2010-2-19 14:22

是这样的,我在变量dst中存储目标目录(目标目录只有一个),在变量src中存放源文件或源文件夹(源文件或文件夹有多个,用分号隔开)


处理过程:
如果源文件或文件夹的数目大于等于2(
    循环分析出每一个源文件或文件夹(
        如果源是文件夹(
            在目标文件夹中建立子目录
            将源文件夹中的内容拷贝到新建立的子目录中
       ) else (
            直接将源文件拷贝到目标文件夹
       )
    )
) else (
     直接将源文件或文件夹里的内容拷贝到目标文件夹


我写的思路能看懂吗?
作者: summerflower    时间: 2010-2-19 16:19

  1. @echo off
  2. setlocal
  3. setlocal enabledelayedexpansion
  4. rem 从文件中读取目标目录和源文件或文件夹
  5. rem 文件的第一行是目标目录,后面的行是源文件或文件夹
  6. rem 不管是目标还是源的文件夹,最后都不以"\"结尾
  7. set srccnt=0
  8. set dst=
  9. set src=
  10. for /f "delims=" %%a in (1.txt) do (
  11.         if not defined dst (
  12.                 set dst=%%a
  13.         ) else (
  14.                 if defined src (
  15.                         set src=!src!;%%a
  16.                 ) else (
  17.                         set src=%%a
  18.                 )
  19.                 set /a srccnt+=1
  20.         )
  21. )
  22. set srctmp=
  23. if %srccnt% geq 2 (
  24.         :loopSrc
  25.         set srcChar=!src:~0,1!
  26.         set src=!src:~1!
  27.         if "!srcChar!"==";" (
  28.         
  29.                 rem 判断srctmp是文件还是目录
  30.                 set isDir=true
  31.                 set cnt=0
  32.                 set lst=
  33.                 for /f %%a in ('dir /b !srctmp!') do (
  34.                         set lst=%%~dpnxa
  35.                         set /a cnt+=1
  36.                 )
  37.                 if !cnt!==1 (
  38.                         if /i !lst!==!srctmp! (
  39.                                 set isDir=false
  40.                         )
  41.                 )
  42.                
  43.                 rem 如果要拷贝的源是目录,那么先建立子目录,再拷贝。
  44.                 rem 如果是文件,直接将源拷到目标文件夹就可以了
  45.                 if !isDir!==true (
  46.                         for /d %%a in ("!srctmp!") do (
  47.                                 md !dst!\%%~na
  48.                                 xcopy /s /e !srctmp! !dst!\%%~na\>nul
  49.                         )
  50.                 ) else (
  51.                         copy !src! !dst!\>nul
  52.                 )
  53.                
  54.                 set srctmp=
  55.         ) else (
  56.                 if defined srctmp (
  57.                         set srctmp=!srctmp!!srcChar!
  58.                 ) else (
  59.                         set srctmp=!srcChar!
  60.                 )
  61.         )
  62.         if defined src (
  63.                 goto loopSrc
  64.         ) else (
  65.                 goto endLoopSrc
  66.         )
  67.         :endLoopSrc
  68.         rem 判断是文件还是目录
  69.         set cnt=0
  70.         set lst=
  71.         set isDir=true
  72.         for /f "delims=" %%a in ('dir /b !srctmp!') do (
  73.                 set /a cnt+=1
  74.                 set lst=%%~dpnxa
  75.         )
  76.         
  77.         if !cnt!==1 (
  78.                 if /i !srctmp!==!lst! (
  79.                         set isDir=false
  80.                 )
  81.         )
  82.         
  83.         rem 如果要拷贝的源是目录,那么先建立子目录,再拷贝。
  84.         rem 如果是文件,直接将源拷到目标文件夹就可以了
  85.         if !isDir!==true (
  86.                 for /d %%a in ("!srctmp!") do (
  87.                         md !dst!\%%~na
  88.                         xcopy !srctmp! !dst!\%%~na>nul
  89.                 )
  90.         ) else (
  91.                 copy !srctmp! !dst!\>nul
  92.         )
  93.         
  94.         
  95. ) else (
  96.         xcopy /s /e %src% %dst%\>nul
  97. )
  98. endlocal
复制代码

1.txt的内容
  1. d:\mydocument\dos练习\测试
  2. d:\mydocument\dos练习\临时笔记
  3. d:\mydocument\dos练习\1.bat
复制代码

[ 本帖最后由 summerflower 于 2010-2-19 16:20 编辑 ]
作者: Seter    时间: 2010-2-20 09:02

我怎么完全看不懂吖...
作者: summerflower    时间: 2010-2-20 13:45

看不懂就算了吧,帮我看看第一段代码的问题如何解决
我把goto换成了call
结果call的行为跟goto是一样的
作者: Seter    时间: 2010-2-22 10:34

换成了call。您真聪明吖。
您。语言表达能力比我还差。
劝您。去论坛搜索一下。
作者: terse    时间: 2010-2-22 11:23

这样简单点行不?
  1. @echo off&setlocal enabledelayedexpansion
  2. for /f "delims=" %%a in (1.txt) do (
  3.     if defined dst (
  4.        if exist "%%a\" (
  5.           xcopy "%%a" /Y /H /R "!dst!\%%~nxa" >nul 2>nul
  6.           ) else copy "%%a" "!dst!"
  7.        ) else  set "dst=%%a"
  8.    )
  9. )
  10. pause
复制代码

作者: Seter    时间: 2010-2-22 11:30

terse大大真是助人为乐 =v=
还有terse大大语文满分的吧 =v=  帮我解释一下LZ的意思
作者: Batcher    时间: 2010-2-22 12:27     标题: 回复 7楼 的帖子

为了方便他人查看,能否把问题描述和代码全部更新到顶楼?
作者: summerflower    时间: 2010-2-23 14:34

非常感谢terse,你的代码可行

只是想问一下xcopy "%%a" /Y /H /R "!dst!\%%~nxa" >nul 2>nul这条语句为什么还要加上2>nul呢?

也谢谢Secter,其实我要实现的功能,简单的说,就是把源文件或文件夹拷贝到目标目录中去
作者: summerflower    时间: 2010-2-23 14:36

还有,我想知道的是,如果在迫不得已的情况下,我必须在复合语句中使用跳转,那么上面乱跳的情况还是会出现

请问各位高手怎么解决?
作者: namejm    时间: 2010-2-23 15:24

  实际上,这个代码并没有乱跳,而是遵循了cmd语句执行的基本规则:

  1、for语句中,in……do之间括号中的元素个数决定了do之后括号内所有语句的执行次数,只有当do后所有语句都执行完毕之后,才跳出for循环,执行for语句的下一条语句;
  2、goto语句是跳转语句,决定了流程的走向,当它跳转到指定标签后,就自顶向下,逐一执行该标签之后的所有语句,直到文件结尾,除非其间碰到下一条跳转语句才改变这个流程方向。
  3、goto循环的优先级高于for循环,也就是说,如果在for语句内部有goto流程跳转语句,将遵循goto的跳转流程,而不必等待for内部循环是否执行完毕。

  根据这3条规则,再来分析顶楼的代码就十分好理解了(为了方便演示整个过程,请在最后添加暂停语句pause。):

  1、当输入abc的时候,在for语句内部碰到了第一条if语句,判断的结果是str被赋值了,所以,执行 :loopstr 标签段。需要注意的是,:loopstr标签段的作用范围是 :loopstr 和 :endloopstr 之间的语句。在 :loopstr 标签段中,str的值逐次被去掉第一位字符,最终得到空值,结果, :loopstr 标签段循环完之后,就跳转到 :endloopstr 标签段。:endloopstr 标签段的作用范围是作用至文件尾,所以,会执行其后的5行代码,结果,就在屏幕上显示了双横线。回过头来看,在str被赋值的时候,这条for语句是被分成了三大块来执行的:第1块是整个for语句,无需多说;第2块是:loopstr标签段,第3块是 :endloopstr 标签段。由于goto语句的跳转,for语句就被割裂成这3大块来执行,与call调用了一段子程序之后会回过头来执行它的下一句大不一样,goto语句是跳出去之后就不回头的(除非另一条跳转语句又让它跳回来),所以,当str被赋值的时候,for语句不会在内部执行3次do后的语句,而是在第1次执行的时候,就用goto语句跳出了for循环的;

  2、当str没有被赋值的时候,for语句内部do后的语句块,第一条if语句没有执行else之前的语句,而是执行了else之后的语句,所以,第1次会显示双横线;因为没有goto语句跳转,for语句继续在内部循环,再次提示你输入,结果会重复第1条或本条的过程,如此循环往复,当每次都没有输入任何字符的时候,for语句将在屏幕上显示3次双横线。换而言之,for把3次内部循环完整地执行了。
作者: 基拉freedom    时间: 2010-2-23 19:14

) else (
                        goto endLoopStr
                )
                :endLoopStr
不是纯属多余吗?
作者: bat_521    时间: 2010-9-20 23:39     标题: 回复 17楼 的帖子

namejm  久闻大名,怪不得youxi01站长把 站长的位置交与你托管.你确实水平大大地高.从你对语句的分析和讲解,可以看出你的水平厉害,表达能力特别好,让人一看就懂.批处理之家让你来管,绝对可靠
!




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