Board logo

标题: [原创] [批处理命令一日一教学 续](41)调用子过程或外部程序:call [打印本页]

作者: Hello123World    时间: 2011-11-28 21:48     标题: [批处理命令一日一教学 续](41)调用子过程或外部程序:call

【原】[一日一教学]批处理系列帖子索引 http://bbs.bathome.net/thread-2576-1-1.html
【续】[一日一教学]批处理系列帖子索引 http://bbs.bathome.net/thread-13798-1-1.html


帮助信息:
  1. 从批处理程序调用另一个批处理程序。
  2. CALL [drive:][path]filename [batch-parameters]
  3.   batch-parameters   指定批处理程序所需的命令行信息。
  4. 如果命令扩展被启用,CALL 会如下改变:
  5. CALL 命令现在将卷标当作 CALL 的目标接受。语法是:
  6.     CALL:label arguments
  7. 一个新的批文件上下文由指定的参数所创建,控制在卷标被指定
  8. 后传递到语句。您必须通过达到批脚本文件末两次来 "exit" 两次。
  9. 第一次读到文件末时,控制会回到 CALL 语句的紧后面。第二次
  10. 会退出批脚本。键入 GOTO /?,参看 GOTO :EOF 扩展的描述,
  11. 此描述允许您从一个批脚本返回。
  12. 另外,批脚本文本参数参照(%0、%1、等等)已如下改变:
  13.      批脚本里的 %* 指出所有的参数(如 %1 %2 %3 %4 %5 ...)
  14.      批参数(%n)的替代已被增强。您可以使用以下语法:
  15.          %~1         - 删除引号("),扩展 %1
  16.          %~f1        - 将 %1 扩展到一个完全合格的路径名
  17.          %~d1        - 仅将 %1 扩展到一个驱动器号
  18.          %~p1        - 仅将 %1 扩展到一个路径
  19.          %~n1        - 仅将 %1 扩展到一个文件名
  20.          %~x1        - 仅将 %1 扩展到一个文件扩展名
  21.          %~s1        - 扩展的路径只含有短名
  22.          %~a1        - 将 %1 扩展到文件属性
  23.          %~t1        - 将 %1 扩展到文件的日期/时间
  24.          %~z1        - 将 %1 扩展到文件的大小
  25.          %~$PATH:1   - 查找列在 PATH 环境变量的目录,并将 %1
  26.                        扩展到找到的第一个完全合格的名称。如果
  27.                        环境变量名未被定义,或者没有找到文件,
  28.                        此修改符会扩展到空字符串
  29.     可以组合修改符来取得多重结果:
  30.         %~dp1       - 只将 %1 扩展到驱动器号和路径
  31.         %~nx1       - 只将 %1 扩展到文件名和扩展名
  32.         %~dp$PATH:1 - 在列在 PATH 环境变量中的目录里查找 %1,
  33.                       并扩展到找到的第一个文件的驱动器号和路径。
  34.         %~ftza1     - 将 %1 扩展到类似 DIR 的输出行。
  35.     在上面的例子中,%1 和 PATH 可以被其他有效数值替换。
  36.     %~ 语法被一个有效参数号码终止。%~ 修定符不能跟 %*
  37.     使用
复制代码
.


命令概括:
call,意为: 电话;呼叫;要求;访问。引申为“调用”。
batch-parameter,意为“批处理参数”。
label,意为“标签”。
argument,意为“参数”。

call表明,批处理其实也是有函数的。

参数详解:
1、从批处理程序调用另一个批处理程序(外部函数)?

新建两个批处理程序,分别命名为test.bat、hello.bat。
test.bat
  1. echo %1 %2
  2. pause
复制代码
.


hello.bat
  1. @echo off
  2. call test.bat hello world
  3. pause
复制代码
运行hello.bat,调用test.bat,结果显示。
[attach]4730[/attach].

从结果中可以看出,hello.bat执行了4条语句,第一条关闭回显(@echo off),第二条输出hello world,第三条、第四条暂停并提示(pause)。
从这里可以看出,从批处理程序调用另一个批处理程序的执行流程:先执行原批处理中的代码,当遇到调用时再执行完被调用的批处理中的所有代码,最后返回到原批处理再执行call语句之后的代码。这种执行流程,同样适用于call 调用标签(内部函数)


2.第一节test.bat中%1,%2是什么意思?

要明白test.bat中%1、%2是什么意思,我们得结合hello.bat中“call test.bat hello world”和test.bat中“echo %1 %2”来看。

hello.bat中的类容不变,试着修改test.bat中的内容。
test.bat
  1. echo  %2
  2. pause
复制代码
.

再次执行hello.bat,结果:
  1. world
  2. 请按任意键继续. . .
复制代码
.

“hello”不见了,只显示了“world”,这给人一种感觉,好像%1代表了“hello”,%2代表了“world”——事实上也确实如此。

我们可以将%1~%9这九个参数看成是批处理的形参,在这个例子中,%1,%2就是形参,而“hello”、 “world”就是实参。

这种参数的传递,执行流程就是在原批处理中将实参传递到被调用批处理中的形参中。



例如:
将hello.bat,test.bat进行如下修改。

hello.bat
  1. @echo off
  2. call test.bat 3 9
  3. pause
复制代码
.

test.bat
  1. Set /a n=%1+%2
  2. echo %n%
  3. pause
复制代码
.

运行hello.bat,结果返回12。

实参中的分隔符可以是空格、逗号、分号、等于号,“call test.bat 3 9”写成“call test.bat 3,9”、“call test.bat 3;9”、“call test.bat 3=9”都是可以的。


3.调用一个内部函数(标签)

如果把“被调用批处理”看成是外部函数,那么标签就可以看成是内部函数。

修改hello.bat的内容:
  1. @echo off
  2. call :1 "hello"
  3. pause
  4. exit
  5. :1
  6. echo.%~1
复制代码
.

call调用标签时冒号(:)不可以省略,和goto不同(goto跳转时,冒号可有可无)。




4.函数调用中非实参形参对应关系的变量值的相互传递。

hello.bat
  1. @echo off
  2. Set n=1
  3. call :1 "hello"
  4. pause
  5. exit
  6. :1
  7. echo.%~1
  8. echo %n%
复制代码
代码的执行结果:
  1. hello
  2. 1
  3. 请按任意键继续. . .
复制代码
.

以上结果说明,内部函数中,变量n的值,可以在主函数中定义,在被调用函数中输出。——这种结果,同样会出现在外部函数中(一个批处理调用另一个批处理)。


再次修改hello.bat
  1. @echo off
  2. call :1 "hello"
  3. echo %n%
  4. pause
  5. exit
  6. :1
  7. echo.%~1
  8. Set n=1
复制代码
.

结果:
  1. hello
  2. 1
  3. 请按任意键继续. . .
复制代码
以上结果说明,内部函数中,变量n的值,也可以在被调用函数中定义,在主函数中输出。——这种结果,同样会出现在外部函数中(一个批处理调用另一个批处理)。




5.嵌套调用

嵌套调用就是一个被调用的函数中还有一个调用其它函数的命令,就好像小时候玩的那工兵、班长、排长、连长、团长……,团长 call 连长,连长 call 排长,……,班长 call 工兵,然后工兵才开始干活。

修改两个批处理的内容:

hello.bat
  1. @echo off
  2. call test.bat world
  3. echo %m%
  4. pause&exit
复制代码
.

test.bat
  1. Echo %1
  2. Set m=1
  3. call :1 hello
  4. pause&exit /b
  5. :1
  6. echo %1
复制代码
.

结果:
  1. world
  2. hello
  3. 请按任意键继续. . .
  4. 1
  5. 请按任意键继续. . .
复制代码
.

这里,test.bat是被调用的函数,但它自身又包含一个内部子函数(:1)——这就是函数的嵌套。

可以看出虽然test.bat中有两个%1,但是它们的值并不相同,这说明父函数的形参并不等于子函数的形参。


注意:这里exit /b 是用来退出子函数的,不加/b参数就会退出整个cmd.exe(区别就是,加/b父函call之后命令还会执行,不加/b父函数call之后的命令就不会执行了)。
可以把test.bat中的exit /b 替换为 exit 体会一下。

6.函数的递归调用

http://bbs.bathome.net/thread-1264-1-6.html
这篇教程由pusofalse提供。


扩展阅读:

1.利用call实现变量延迟。
  1. @echo off
  2. for /l %%i in (1 1 5) do (
  3. Set n=%%i
  4. set /a n+=1
  5. call echo %%n%%
  6. )
  7. pause
复制代码
.

2.call和for一起使用。
  1. ::在文件路径前加“this is a text”
  2. @echo off
  3. For /r %%i in (*.txt) do call :1 %%i
  4. pause
  5. :1
  6. Set n=This is a text:%1
  7. echo %n%
复制代码
.

第二种方法的作用其实更大。但是第一种方法用的却更多。
作者: ivor    时间: 2012-2-10 13:26

  1. call echo %%n%%
复制代码
这个不错
作者: 迷彩的SF    时间: 2012-2-12 23:12

回复 1# Hello123World


    总算明白%1~9的用法了
作者: flaven    时间: 2012-5-8 19:51

对批处理越来越佩服了
作者: wangx    时间: 2013-9-15 17:49

学到很多,每天都进步一点,谢谢分享。
作者: wangxiaodong    时间: 2014-4-2 20:27

深有体会啊!遇到变量引用时非常有用1# Hello123World
作者: wxc2k14329    时间: 2014-4-5 18:21

最后一例显示为:
This is a text:%1     ???
作者: wrsbj    时间: 2015-1-2 15:53

批处理博大精深,学习了
作者: Bat_s    时间: 2015-1-21 17:18

@echo off
rem 用^call命令去理解%*这些常理的应用
call :x 1 10
pause&exit
:x
for /l %%i in (%1,%1,%2) do echo %%i
作者: 1055367558    时间: 2017-8-19 10:50

call echo %%n%%还一定要加两层%%
作者: 1212112    时间: 2017-9-26 21:50

为什么是要加两层%呢,是什么意思呢?
作者: 1212112    时间: 2017-9-27 11:53

有一些行确实看不明白,希望指教一下
call echo %%n%% 这句是什么意思呢?
call echo 怎么理解?
%%n%% 又怎么理解?

谢谢
作者: ai20110304    时间: 2018-8-29 22:48

嵌套调用,有些地方又叫函数链式调用

批处理中的变量定义范围好像没的javascript那么受限制一样,全局或局部




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