批处理之家's Archiver

Hello123World 发表于 2011-11-28 21:48

[批处理命令一日一教学 续](41)调用子过程或外部程序:call

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


[color=Green]帮助信息:[/color][code]从批处理程序调用另一个批处理程序。

CALL [drive:][path]filename [batch-parameters]

  batch-parameters   指定批处理程序所需的命令行信息。

如果命令扩展被启用,CALL 会如下改变:

CALL 命令现在将卷标当作 CALL 的目标接受。语法是:

    CALL:label arguments

一个新的批文件上下文由指定的参数所创建,控制在卷标被指定
后传递到语句。您必须通过达到批脚本文件末两次来 "exit" 两次。
第一次读到文件末时,控制会回到 CALL 语句的紧后面。第二次
会退出批脚本。键入 GOTO /?,参看 GOTO :EOF 扩展的描述,
此描述允许您从一个批脚本返回。

另外,批脚本文本参数参照(%0、%1、等等)已如下改变:


     批脚本里的 %* 指出所有的参数(如 %1 %2 %3 %4 %5 ...)

     批参数(%n)的替代已被增强。您可以使用以下语法:

         %~1         - 删除引号("),扩展 %1
         %~f1        - 将 %1 扩展到一个完全合格的路径名
         %~d1        - 仅将 %1 扩展到一个驱动器号
         %~p1        - 仅将 %1 扩展到一个路径
         %~n1        - 仅将 %1 扩展到一个文件名
         %~x1        - 仅将 %1 扩展到一个文件扩展名
         %~s1        - 扩展的路径只含有短名
         %~a1        - 将 %1 扩展到文件属性
         %~t1        - 将 %1 扩展到文件的日期/时间
         %~z1        - 将 %1 扩展到文件的大小
         %~$PATH:1   - 查找列在 PATH 环境变量的目录,并将 %1
                       扩展到找到的第一个完全合格的名称。如果
                       环境变量名未被定义,或者没有找到文件,
                       此修改符会扩展到空字符串

    可以组合修改符来取得多重结果:

        %~dp1       - 只将 %1 扩展到驱动器号和路径
        %~nx1       - 只将 %1 扩展到文件名和扩展名
        %~dp$PATH:1 - 在列在 PATH 环境变量中的目录里查找 %1,
                      并扩展到找到的第一个文件的驱动器号和路径。
        %~ftza1     - 将 %1 扩展到类似 DIR 的输出行。

    在上面的例子中,%1 和 PATH 可以被其他有效数值替换。
    %~ 语法被一个有效参数号码终止。%~ 修定符不能跟 %*
    使用
[/code].


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

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

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

新建两个批处理程序,分别命名为test.bat、hello.bat。
test.bat[code]
echo %1 %2
pause[/code].


hello.bat[code]@echo off
call test.bat hello world
pause
[/code]运行hello.bat,调用test.bat,结果显示。
[attach]4730[/attach].

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

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[code]echo  %2
pause[/code].

再次执行hello.bat,结果:[code] world
请按任意键继续. . .[/code].

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

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

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


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

hello.bat[code]@echo off
call test.bat 3 9
pause[/code].

test.bat[code]Set /a n=%1+%2
echo %n%
pause[/code].

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

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

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

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

修改hello.bat的内容:[code]@echo off
call :1 "hello"
pause
exit
:1
echo.%~1[/code].

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



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

hello.bat[code]@echo off
Set n=1
call :1 "hello"
pause
exit
:1
echo.%~1
echo %n%[/code]代码的执行结果:[code]hello
1
请按任意键继续. . .[/code].

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

再次修改hello.bat[code]@echo off
call :1 "hello"
echo %n%
pause
exit
:1
echo.%~1
Set n=1[/code].

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



5.嵌套调用

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

修改两个批处理的内容:

hello.bat[code]@echo off
call test.bat world
echo %m%
pause&exit[/code].

test.bat[code]Echo %1
Set m=1
call :1 hello
pause&exit /b
:1
echo %1
[/code].

结果:[code]world
hello
请按任意键继续. . .
1
请按任意键继续. . .[/code].

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

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

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

6.函数的递归调用

[url]http://bbs.bathome.net/thread-1264-1-6.html[/url]
[color=Red]这篇教程由pusofalse提供。[/color]


[color=Green]扩展阅读:[/color]

1.利用call实现变量延迟。[code]@echo off
for /l %%i in (1 1 5) do (
        Set n=%%i
        set /a n+=1
        call echo %%n%%
)
pause[/code].

2.call和for一起使用。[code]::在文件路径前加“this is a text”
@echo off
For /r %%i in (*.txt) do call :1 %%i
pause
:1
Set n=This is a text:%1
echo %n%
[/code].

第二种方法的作用其实更大。但是第一种方法用的却更多。

ivor 发表于 2012-2-10 13:26

[code]call echo %%n%%[/code]这个不错

迷彩的SF 发表于 2012-2-12 23:12

[b]回复 [url=http://bbs.bathome.net/redirect.php?goto=findpost&pid=97755&ptid=14852]1#[/url] [i]Hello123World[/i] [/b]


    总算明白%1~9的用法了

flaven 发表于 2012-5-8 19:51

对批处理越来越佩服了

wangx 发表于 2013-9-15 17:49

学到很多,每天都进步一点,谢谢分享。

wangxiaodong 发表于 2014-4-2 20:27

[b] 深有体会啊!遇到变量引用时非常有用[url=http://bbs.bathome.net/redirect.php?goto=findpost&pid=97755&ptid=14852]1#[/url] [i]Hello123World[/i] [/b]

wxc2k14329 发表于 2014-4-5 18:21

最后一例显示为:
This is a text:%1     ???{:3_53:}

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那么受限制一样,全局或局部

页: [1]

Powered by Discuz! Archiver 7.2  © 2001-2009 Comsenz Inc.