Board logo

标题: [其他] 在call的子程序中直接调用主程序的疑惑 [打印本页]

作者: qzwqzw    时间: 2012-4-18 11:47     标题: 在call的子程序中直接调用主程序的疑惑

  1. @echo off
  2. if [%1]==[call] (echo 在批处理主程序中运行 & exit /b)
  3. set prog=%0
  4. call :子程序
  5. echo.end
  6. pause
  7. goto :eof
  8. :子程序
  9. if [%1]==[call] (echo 在批处理子程序中运行 & exit /b)
  10. echo.%0---%~s0---%~f0
  11. rem 以下调用将程序的命令行指针转向了子程序而非主程序
  12. rem 这跟我以前的用法和认识相违背,是哪里出了问题?
  13. %prog% call
复制代码

作者: powerbat    时间: 2012-4-18 12:32

我知道%0并不一定表示批处理“文件”路径,而是实际键入的“程序”名(包括标签名),但可以用%~f0、%~s0等扩展成文件路径,曾经的verybat论坛有相关帖子论述。
也知道调用bat子程序时,如果不加call,调用位置后面的代码将无法执行。
  1. main.bat
  2. ==========
  3. @echo off
  4. echo;begin
  5. sub.bat
  6. rem call sub.bat
  7. echo;到这里了
  8. echo;end
  9. pause
  10. sub.bat
  11. ==========
  12. echo.%0---%~s0---%~f0
  13. pause
复制代码
ntcmds.chm中对call的解释
Call
从一个批处理程序调用另一个批处理程序,并且不终止父批处理程序。

不使用call有点类型于linux的exec,子程序把当前程序给替换了?
楼主的代码加一个call就正常了,但不明白不加时为什么是那样的结果。难道cmd重调用bat时记住了“子程序”在文件中的偏移位置,直接从偏移处开始执行代码?
作者: neorobin    时间: 2012-4-18 14:20

测试得到一些结果:
  1. %0 Params
复制代码
在子过程中被解释成标号行, 而在主程序(文件级)中始终被解释成调用自身.

另外, 用 %0 作赋值的情况:

set prog=%0 处于 %prog% callParams !prog! callParams
在子过程中 标号行 标号行
在主程序(文件级)中 调用子过程自身 调用主程序(文件级)


测试代码:
  1. @echo off
  2. REM echo %%0 Params
  3. REM (%0 Params) & rem 将调用主程序(文件级)自身, 而陷入死循环
  4. setlocal enabledelayedexpansion
  5. echo,& echo,@ Main code & echo,
  6. echo,%%0=%0
  7. echo,Params=%*
  8. if [%1]==[Params] (echo 在批处理主程序中运行 & exit /b)
  9. (set prog=%0) & rem 处于主程序(文件级)中
  10. echo prog=%prog%
  11. echo,call :子程序
  12. call :子程序
  13. echo,& echo,End of Main code & echo,
  14. pause
  15. goto :eof
  16. :子程序
  17. echo,& echo,@ Sub code & echo,
  18. echo,%%0=%0
  19. echo,%%~s0=%~s0
  20. echo,%%~f0=%~f0
  21. echo,Params=%*
  22. if [%1]==[Params] (echo 在批处理子程序中运行 & exit /b)
  23. echo prog=%prog%
  24. echo,%%0 Params
  25. %0 Params
  26. REM 上行被解释成标号行
  27. REM (set prog=%0) & rem 处于子过程中
  28. echo prog=%prog%
  29. echo,^^!prog^^! Params
  30. !prog! Params
  31. echo,%%prog%% Params
  32. %prog% Params
  33. echo,& echo, end of sub code & echo,
  34. exit /b
复制代码

作者: qzwqzw    时间: 2012-4-18 21:38

经过与原来的代码对比
终于发现了不同之处
  1. @echo off
  2. if [%1]==[call] (echo 在批处理主程序中运行 & pause & exit /b)
  3. call :子程序1
  4. echo.
  5. call :子程序2
  6. echo.
  7. echo.主程序结束
  8. pause
  9. goto :eof
  10. :子程序1
  11. if [%1]==[call] (echo 在批处理子程序2中运行 & pause & exit /b)
  12. echo 以下调用将程序的命令行指针转向了主程序,区别在于调用发生在一个子句中
  13. echo if [1]==[1] %~f0 call
  14. if [1]==[1] %~f0 call
  15. :子程序2
  16. if [%1]==[call] (echo 在批处理子程序1中运行 & pause & exit /b)
  17. echo 以下调用将程序的命令行指针转向了主程序,区别在于调用发生在一个语句块中
  18. echo ^( %~f0 call ^)
  19. ( %~f0 call )
复制代码
另外谈一下为什么要用这个特性
我主要用它做子程序的错误抛出处理
也就是说在某个被call的子程序中
如果发现错误就使用 "%~s0 :Error 错误代码 错误信息" 的形式
把这个错误抛出到程序的错误处理模块中
当然这个错误需要在程序的起始位置加一句错误捕捉语句
if [%1]==[:Error] goto :Error
之所以不用call抛出错误
是因为我在处理了错误之后是不准备返回子程序的
而是直接使用 exit /b 错误代码 的形式退回了主程序

原来一直使用本楼的写法
即在直接调用之间都会有一些判断语句
所以没有遇到问题
因此就形成了刻板的印象
没想到call中的%~s0调用会重置到子程序的起始位置
作者: applba    时间: 2012-4-20 22:42

%0返回的最近的调用者。
作者: qzwqzw    时间: 2012-4-21 23:03

回复 5# applba
不解其意




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