解决set /p yn= 接受键盘输入导致ECHO 处于关闭状态的问题

今天写了一个自动更新程序的批处理脚本,但是有个变量一直赋值有问题。弄了一个下午终于找到原因及解决方法:

----转载要说明来自:博客园--邦邦酱好 哦

 

有问题的代码如下:

@echo off
echo.
set  choice=1
::::::::::::::::::::::::::::::::::::::::::::::
:::::::::::::::程序包上传FTP::::::::::::::::::
::::::::::::::::::::::::::::::::::::::::::::::
if "%choice%"=="1" (
    echo 请确认你已经把程序包放到本地指定目录下(y/n):
    set /p yn=
    echo %yn%
    if /i "%yn%"=="n" (
        set yn=""
        goto end
    )
    echo 开始上传本地最新的程序包到服务器上...
    echo 上传完毕
)

:end
set choice=
echo 脚本终止!

连续运行4次,中间有2次说“ECHO处于关闭状态”,然后程序就判断失败了,这是为什么呢?

多次试验发现,如果语句set /p yn=   是在if语句外部,就不会发生这样的问题。

 

解决代码:

增加了setlocal enabledelayedexpansion,再改%yn%为!yn!。

@echo off&setlocal enabledelayedexpansion 

echo.
set choice=1
::::::::::::::::::::::::::::::::::::::::::::::
:::::::::::::::程序包上传FTP::::::::::::::::::
::::::::::::::::::::::::::::::::::::::::::::::
if "%choice%"=="1" (
    echo 请确认你已经把程序包放到本地指定目录下(y/n):
    set /p yn=
    echo !yn!
    if /i "!yn!"=="n" (
        set yn=
        goto end
    )
    echo 开始上传本地最新的程序包到服务器上...
    ::call Upload_Ftp.bat
    echo 上传完毕
)

:end
echo 脚本终止!

 

查了一个下午,发现原因如下:

批处理有一种机制是变量延迟,比如

@echo off
set a=4
set a=5&echo %a%
pause 

打印的结果会是a=4,而不是a=5,因为在读取了一条完整的语句(set a=4)之后,不立即对该行的变量赋值,而会在某个单条语句(set a=5&echo %a%)执行之前再进行赋值操作。也就是说“延迟”了对变量的赋值。

在cmd执行命令前会对脚本进行预处理,其中有一个过程是变量识别过程,在这个过程中,如果有两个%括起来的如%value%类似这样的变量,就会对其进行识别,并且查找这个变量对应的值,再而将值替换掉这个变量,这个替换值的过程,就叫做变量扩展,然后再执行命令。一般是对静态变量进行值的替换。

setlocal enabledelayedexpansion 就是延迟本地环境变量扩展,在cmd执行中,发生动态的一种情况是在 for语句,if语句中进行变量赋值,在动态变量赋值过程中,如果不主动开启延迟本地环境变量扩展,是不会对变量进行预处理的。

在上文第一段代码中,由于在语句(if /i "!yn!"=="n")之前没有对yn变量进行赋值,所以得到“ECHO处于关闭状态”的结果。

比如上方第三段代码,如果启动了变量延迟并把set a=5&echo%a%改为set a=5&echo!a!,所以批处理能够感知到动态变化,即不是先给该行变量赋值,而是在运行过程中给变量赋值,因此此时a的值就是5了。

所以我们就要在第一段代码中加入setlocal enabledelayedexpansion语句,开启延迟本地环境变量扩展,使得yn变量在if的动态赋值过程中能够被赋值。

同时注意开启延迟本地环境变量扩展后,变量需要用!!进行引用。

 

posted @ 2014-09-30 14:58  邦邦酱好  阅读(3284)  评论(9编辑  收藏  举报