call
-------siwuxie095
call
调用另一个批处理程序或自身程序段,调用完,程序会回到原来 call 的地方继续执行
如果在脚本或批处理文件外使用 call,则不会在命令行起作用
语法
call [[Drive:][Path] FileName [BatchParameters]] [:Label [Arguments]]
参数说明:
[Drive:][Path] FileName
指定要调用的批处理程序的位置(路径)和名字,FileName 参数必须有 .bat 和 .cmd 扩展名
BatchParameters
指定批处理程序所需的任何命令行信息,包括命令行选项、文件名、批处理参数
(即从 %0 到 %9)或 变量(如 %baud%)
call :Lable Arguments
调用本文件内命令段(目标程序段),相当于子程序。
(1)被调用的命令段以标签 :label 开头,以 goto :eof 结尾,调用完回到原来 call 的地方
继续执行下去。
(2)假如被调用的命令段(子程序)以 exit 结尾,调用完子程序后就会直接退出,
不会回到原来 call 的地方。
(3)假如被调用的命令段没有 goto :eof 或 exit 等退出标志,程序在调用子程序后,
会一直执行到整个程序末尾,然后才会回到原来 call 的地方继续执行下去。
Arguments
对于以 :Label 开始的批处理程序,指定要传递给其新实例的所有命令行信息,包括
命令行选项、文件名、批处理参数(即 %0 到 %9) 或 变量(如 %baud%)
注意事项:
不要在 call 命令中使用管道和重定向符号。
可以创建调用自身的批处理程序,但是必须提供退出条件,
否则父子程序将循环上千次
在启用命令扩展的情况下(即默认情况下),call 将接受 Label 参数作为
调用目标,语法:
call :Label Arguments
call [Drive:][Path] FileName
如: 测试.bat 调用桌面上 test 文件夹内的 goto.bat
sublime中:
测试效果一览:
再如:同一文件夹下的 a.bat 和 b.bat
@echo off set /p var=请选择(Y/N): if /i "%var%"=="Y" call b.bat echo a.bat 执行完毕 pause >nul
@echo off echo Hello World start explorer.exe echo b.bat 执行完毕 pause >nul
sublime中:
运行 a.bat 后,效果一览(同时还打开了 资源管理器):
子程序语法:
:label
command1
command2
…
commandn
子程序段中,参数 %0 指标签 :label
在主程序中,注意使用 goto exit goto :eof 等跳转语句,避免
误进入其他子程序
主程序和子程序中的所有变量都是全局变量,作用范围是整个批处理程序
主程序传递至子程序的参数在call语句中指定,在子程序中用 %0 – %9 的
形式调用,子程序返回主程序的数据只需在调用结束后,直接引用即可
如:test.bat
@echo off set /p a=请输入一个数字 : if /i %a%==0 (call :o ) else (call :t) :o echo Hello World pause>nul & exit :t echo This is a bat program pause>nul & exit
sublime中:
运行效果一览:
goto 和 call :
虽然都可以跳转,但说到底,goto 只是跳转而已,跳转到目的地后,
程序按顺序执行下去,不会返回原来的地方。call 调用完程序段后还会
返回原来 call 的地方继续执行下去。
call 调用程序段还可以给参数,goto 则不能。
如:A.bat 和 B.bat
@echo off echo 早上好 goto noon echo 晚安 pause :noon echo 中午好 :night echo 晚上好 pause
@echo off echo 早上好 call :noon echo 晚安 pause :noon echo 中午好 :night echo 晚上好 pause
sublime中:
运行效果一览:
A.bat B.bat
显然,call 不会像 goto 那样打断流程,它只是暂时中断了当前流程
而跳转到目标程序段执行,目标程序段执行完毕,仍回到原来 call 的
地方继续执行下去。所以 call 后经常会有 goto :eof exit 等退出语句
如:
@echo off set var=123 call :loop pause>nul & goto :eof :loop set /a var+=1 echo var=%var% pause>nul
sublime中:
如果没有 goto :eof,则会显示两次数据
@echo off set var=123 call :loop pause>nul :loop set /a var+=1 echo var=%var% pause>nul
比较:
call 带参数:
如:
@echo off call :an Hello 世界 :an echo %1 echo %2 pause>nul
sublime中:
运行一览:
再如:
@echo off call :sub return 你好 echo 子程序返回值 :%return% echo %0 pause>nul :sub set %1=%2 echo %0
sublime中:
运行一览:
主程序里 %0 表示主程序的完整路径,即 "C:\Users\siwux\Desktop\testx.bat"
子程序里 %0 表示子程序的完整路径,即 :sub
对于子程序中的 return 参数,子程序运行结束,主程序可以直接使用,return
全局有效
注意,主程序里不能用 %1- %9 的形式调用子程序参数
如(此调用无效):
@echo off call :sub return 你好 echo %1 echo %2 pause>nul :sub set %1=%2
再如:多数据求和
@echo off set sum=0 call :sub sum 10 20 30 echo 数据求和结果: %sum% pause>nul goto :eof :sub set /a %1=%1+%2 shift /2 if not "%2"=="" goto sub
sublime中:
运行一览:
再如: a.bat 自我调用
call a.bat
sublime中:
运行 a.bat,被执行 1241 次
再如:call 带参数----斐波那契数列
@echo off setlocal enabledelayedexpansion echo. & echo 斐波那契数列 echo. echo 请输入数列总项数 set /p num=(DOS 计算能力不够强大 ,输入的数字不要超过 46): echo. & echo -------------------------------------------------------------- if %num% gtr 46 echo. & echo 输入数据太大 ,按任意键退出 & pause >nul & exit set /a e=!num!-2 set a=1 set b=1 set c=2 if %num% geq 1 call :shuchu !a! if %num% geq 2 call :shuchu !b! for /l %%i in (1,1,%e%) do ( set /a temp=!a!+!b! set /a c+=1 set /a d=!c!%%5 call :shuchu !temp! if !d!==0 echo. set a=!b! set b=!temp! ) echo. & echo. & echo 输出结束 ,按任意键退出 & pause>nul ::这里要注意退出 ,否则程序会继续执行后面的:shuchu 程序段 goto :eof :shuchu set f= %1 echo. set /p pr=!f:~-11!<nul
sublime中:
运行一览:
程序有多个地方用到输出语句,而一个输出就要用到下面两句,用call调用函数来简化
set f= %1 set /p pr=!f:~-11!<nul
%0 往往代表自身
批处理中 %* 指出所有的参数(如 %0 %1 … %n)
关于 %1的扩展(~代表扩展、扩充、增强等):
%~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 可以被其它有效数值替换。
%~ 语法被一个有效参数值终止(如 1 2 3 …)
%~ 不能和 %* 一起使用
如:
@echo off call :sub temp.txt pause & exit :sub echo 删除引号: %~1 echo 扩充到路径: %~f1 echo 扩充到一个驱动器号: %~d1 echo 扩充到一个路径:%~p1 echo 扩充到一个文件名: %~n1 echo 扩充到一个文件扩展名: %~x1 echo 扩充的路径只含有短名: %~s1 echo 扩充到文件属性: %~a1 echo 扩充到文件的日期/时间: %~t1 echo 扩充到文件的大小: %~z1 echo 查找列在 PATH 环境变量的目录,并将第一个参数扩充到找到的第一个完全合格的名称: %~$PATH:1 echo 扩展到驱动器号和路径: %~dp1 echo 扩展到文件名和扩展名: %~nx1 echo 扩展到类似 DIR 的输出行: %~ftza1
sublime中:保存 testx.bat 到桌面
(1)桌面上没有temp.txt,运行一览:
(2)桌面上新建一个 temp.txt,文件属性和运行一览:
(3)桌面没有temp.txt,F盘新建一个temp.txt,同时修改代码:
@echo off call :sub F:\temp.txt pause & exit :sub echo 删除引号: %~1 echo 扩充到路径: %~f1 echo 扩充到一个驱动器号: %~d1 echo 扩充到一个路径:%~p1 echo 扩充到一个文件名: %~n1 echo 扩充到一个文件扩展名: %~x1 echo 扩充的路径只含有短名: %~s1 echo 扩充到文件属性: %~a1 echo 扩充到文件的日期/时间: %~t1 echo 扩充到文件的大小: %~z1 echo 查找列在 PATH 环境变量的目录,并将第一个参数扩充到找到的第一个完全合格的名称: %~$PATH:1 echo 扩展到驱动器号和路径: %~dp1 echo 扩展到文件名和扩展名: %~nx1 echo 扩展到类似 DIR 的输出行: %~ftza1
文件属性和运行一览:
call 高级技巧:
一、嵌套和递归:
如:
汉诺塔问题:n个盘子和3根柱子:A(源)、B(中转)、C(目的)
开始n个盘子从上往下从小到大叠在A柱上(即大盘在下,小盘在上)
要将盘子从A柱移动到C柱,移动过程中可以使用B柱,且只能移动
最顶端的盘子,且盘子只能放在比它本身大的盘子上(即始终保持
大盘在下,小盘在上),且一次只能移动一个盘子
@echo off title 汉诺塔(Hanoi) echo. & echo. echo 汉诺塔程序 setlocal enabledelayedexpansion echo. & set /p plate=请输入盘子数量 : echo. & echo ----------------------------- call :move !plate! A B C echo ----------------------------- echo. & echo 运算结束 ,按任意键退出 & pause>nul :move if %1==1 (echo 盘子从 %2 柱子移动到 %4 柱子) else ( set i=%1 set /a i-=1 call :move !i! %2 %4 %3 echo 盘子从 %2 柱子移动到 %4 柱子 set j=%1 set /a j-=1 call :move !j! %3 %2 %4 )
sublime中:
运行一览:
用 call 递归,嵌套层级测试:
@echo off call :loop 1 :loop echo %1>>temp.txt set /a n=%1+1 call :loop %n%
sublime中:
不用 call 也能实现嵌套,批处理中有一个很特殊的参数 %0,
本身可以带参数运算(和 call 类似)
如:从1开始,每次加1,无限…
@echo off set /a var=%1+1 echo %var% %0 %var%
用call的话(同上):
@echo off :loop set /a var=%1+1 echo %var% call :loop %var%
call 和 %0 的区别:
call 有迭代层级限制,而 %0 没有迭代层级限制
call 调用完程序后会回到原来 call 的地方继续执行,即 call 可以
实现递归,而 %0 仅仅重复调用自身,即 %0 不能实现递归
call 可以只调用程序中的某一小段程序,而 %0 只能调用自身整个程序
在有延迟变量的情况下,%0 调用没几次就达到极限,不能继续执行,
所以 %0 无法实现复杂的程序调用
二、用 call 实现延迟功能
代码1:
@echo off set str=www.cn-dos.net set n=4 echo %%str:~%n%%% pause>nul
代码2:
@echo off set str=www.cn-dos.net set n=4 call echo %%str:~%n%%% pause>nul
sublime中:
运行一览:
代码一并不能得到:cn-dos.net,而是显示: %str:~4%,这是因为cmd
中存在预处理机制,读取:echo %%str:~%n%%% 时,先是迫不及待的脱
去最外层的 %,变为:echo %str:~%n%%,即第二层的 % 变成了字符 %,
自然最后就显示:%str:~4%
代码二通过 call 的延时作用,延时后,cmd会一层层脱去 %,并解释 % 里
的变量,就能正确显示:cn-dos.net
三、call 邪法
@echo off set a=dos set b=a set c=b set d=c echo %a% call echo %%%b%%% call call echo %%%%%%%c%%%%%%% call call call echo %%%%%%%%%%%%%%%d%%%%%%%%%%%%%%% pause>nul
sublime中:
有 n 个 call 时,需要 2^(n+1)-1 个 % 号
【made by siwuxie095】
posted on 2016-12-27 13:22 siwuxie095 阅读(991) 评论(0) 编辑 收藏 举报