My batch window closes when running if exist

2019-06-03 16:53发布

I have a little program and when i run "if exist" it closes, can somebody tell me why? I have checked for syntax errors and none (i think), i will paste my code here and see what you can do.

echo What drive would you like to launch MCEdit on?
set /p DRIVE="Drive: "
if exist "%DRIVE%:\MC\DATA\mcedit\mcedit.exe" (
    set APPDATA=%DRIVE%:\MC\DATA
    start %DRIVE%:\MC\DATA\mcedit\mcedit.exe
) else (
    echo You do not have MCEdit installed on this drive, would you like to install it?
    set /p YesNoIn="[y/n]: "
    if "%YesNoIn%"=="y" goto:yes
    goto:menu
    :yes
    echo Choose the "mcedit.exe" file from a current installation on your pc.
    pause
    call "%DRIVE%\MC\DATA\FileViewer.bat"
    xcopy "%OutCD%" "%DRIVE%:\MC\DATA\mcedit" /E
    echo Done!
    set /p yesnol="Would you like to launch MCEdit now? [y/n]: "
    if "%yesnol%"="y" (
        set APPDATA=%DRIVE%:\MC\DATA
        start %DRIVE%:\MC\DATA\mcedit\mcedit.exe
    )
)

Right after you type the drive it closes, any help?

3条回答
Summer. ? 凉城
2楼-- · 2019-06-03 17:21

You have simple typo in comparison operator in the latter if. Correct to if "%yesnol%"=="y"

查看更多
趁早两清
3楼-- · 2019-06-03 17:23
  1. I'm not sure whether changing APPDATA variable is a good idea.
  2. Missing :menu label in your code.
  3. Important: read and apply http://ss64.com/nt/delayedexpansion.html.
  4. Never use :label nor :: label-like comment inside a command block enclosed in () parentheses

SETLOCAL EnableExtensions EnableDelayedExpansion
      :::
:menu
      :::
echo What drive would you like to launch MCEdit on?
set /p DRIVE="Drive: "
if exist "%DRIVE%:\MC\DATA\mcedit\mcedit.exe" (
    set APPDATA=%DRIVE%:\MC\DATA
    start %DRIVE%:\MC\DATA\mcedit\mcedit.exe
) else (
    echo You do not have MCEdit installed on this drive, would you like to install it?
    set /p YesNoIn="[y/n]: "
    if /I "!YesNoIn!"=="y" (
        echo Choose the "mcedit.exe" file from a current installation on your pc.
        pause
        call "%DRIVE%\MC\DATA\FileViewer.bat"
        xcopy "%OutCD%" "%DRIVE%:\MC\DATA\mcedit" /E
        echo Done^!
        set /p yesnol="Would you like to launch MCEdit now? [y/n]: "
        if /I "!yesnol!"="y" (
            set APPDATA=%DRIVE%:\MC\DATA
            start %DRIVE%:\MC\DATA\mcedit\mcedit.exe
        )
    ) else goto:menu
)
查看更多
一夜七次
4楼-- · 2019-06-03 17:25

The issue that causes the script to exit early is a syntax error in the last if-statement of your else branch. If you run the script from the command line (not by double clicking on it) you'll get the error message:

="y" was unexpected at this time.

Indeed your last if-statement is:

    if "%yesnol%"="y" (

but the cmd parser expects a double "=" sign (==) for comparisons, so you should have:

    if "%yesnol%"=="y" (

The reason why it will see it even if it won't take the else branch is because an if-block (actually, all block of codes delimited by ( ... )) is parsed as if it was one single command written on one line (with each "subcommand" in your block separated with &&). As the parser will process that whole "line" in one go, it will detect whatever syntax error present inside the whole block.

Besides that syntax error, there are some little mistakes you've made in your script. The first one is that it is actually not good to declare labels inside a block of code. You've declared the :yes label inside the if-block in the else branch. A goto inside an if-block will "destroy" the if-context. You maybe won't notice in your code, but consider this example:

@echo off

set var=Let's brake the if statement

IF DEFINED var (
    echo The variable var exists

    IF "%var%"=="Let's brake the if statement" goto :expected

    echo The variable var is not what I would expect though.
    echo You have to change it to something else...
    goto :outside

    :expected
    echo I'm happy with its value. It is at least something I would expect
    echo This is the end of the if-branch

) ELSE (
    echo Strange ... the variable var is not defined.
    echo Indeed: var="%var%"
)
:outside
rem just to get outside

You would expect an output like

The variable var exists  
I'm happy with its value. It is at least something I would expect  
This is the end of the if-branch

but the output will be

The variable var exists
I'm happy with its value. It is at least something I would expect
This is the end of the if-branch
Strange ... the variable var is not defined.
Indeed: var="Let's brake the if statement"

The goto destroyed the if-context. As said earlier, the cmd parser will parse the whole if-block as one command. See it this way: you're asking the parser to abandon the command it was processing (the whole if block with the condition it just checked) and jump to somewhere else. That somewhere else is after the if condition, so it won't even evaluate that one again. So once you're inside a block (espacially if-blocks and for-loops) don't use goto to ignore some piece of code inside that block, use if-statements and put the code to ignore inside the if-block. A goto to jump outside a block of code is not a problem but from the moment the label is inside an if block for example, it can result in unexpected results.

The second mistake is about the variables YesNoIn and yesnol. As I said the whole if block is parsed in one go as one single command. It is not possible to give a variable a new value, and read that new value in the same command with the simple variable expansion %YesNoIn% or %yesnol%. A solution to this problem is delayed expansion (the link also has an example). As I was writing this answer, I saw @Josefz already posted an answer with delayed expansion so I won't repeat it here. But what I would recommend is that you take a look at the choice command. Using the choice command, you won't need delayed expansion. It just sets the errorlevel and there exists a way to check the errorlevel without worrying about delayed expansion: IF ERRORLEVEL n will check if the errorlevel is greater or equal to n. On top of that, choice automatically verifies if the user entered a correct value!
Your script with choice instead of set /p will look like this:

echo What drive would you like to launch MCEdit on?
set /p DRIVE="Drive: "
if exist "%DRIVE%:\MC\DATA\mcedit\mcedit.exe" (
  set APPDATA=%DRIVE%:\MC\DATA
  start %DRIVE%:\MC\DATA\mcedit\mcedit.exe
) else (
  echo You do not have MCEdit installed on this drive, would you like to install it?
  choice /c YN

  REM Y ==> errorlevel = 1   ;     N ==> errorlevel = 2
  if ERRORLEVEL 2 goto:menu

  echo Choose the "mcedit.exe" file from a current installation on your pc.
  pause
  call "%DRIVE%\MC\DATA\FileViewer.bat"
  xcopy "%OutCD%" "%DRIVE%:\MC\DATA\mcedit" /E
  echo Done!
  choice /c YN /m "Would you like to launch MCEdit now? "
  if NOT ERRORLEVEL 2 (
    set APPDATA=%DRIVE%:\MC\DATA
    start %DRIVE%:\MC\DATA\mcedit\mcedit.exe
  )
)

PS: No Enter key needs to be pressed when choice is used.

EDIT: A third mistake is the choice of the variable APPDATA, it is already used by your windows OS in a user's context as you can see here.

查看更多
登录 后发表回答