Warum wird dieses Batch-Skript unerwartet beendet?

Warum wird dieses Batch-Skript unerwartet beendet?

Dieses Batch-Skript wird beendet, wenn %CHECKCONTINUE%durch Nichteingabe in Zeile 13 ( SET /p CHECKCONTINUE=Okay to continue? (y/n):) ein Nullwert angegeben wird. Warum ist das so?

@ECHO OFF
SETLOCAL
TITLE Registry restore script
REM Restores registry settings and disables the cloud

SET %CHECKCONTINUE%=

:listaction
ECHO I'm about to...
ECHO 1.) Remove the registry data that specifies settings for TF2
ECHO 2.) Forcibly disable Steam Cloud.
ECHO.
SET /p CHECKCONTINUE=Okay to continue? (y/n): 

REM No?
IF %CHECKCONTINUE%==n GOTO exit
IF %CHECKCONTINUE%==no GOTO exit

REM Yes?
IF %CHECKCONTINUE%==y GOTO start
IF %CHECKCONTINUE%==yes GOTO start

REM Did they put something else?
IF DEFINED %CHECKCONTINUE% GOTO loop-notvalid

REM Did they not put anything at all?
IF NOT DEFINED %CHECKCONTINUE% GOTO loop-noreply

:start
REM Delete application specific data
REG DELETE HKEY_CURRENT_USER\Software\Valve\Source\tf\Settings /f
REG DELETE HKEY_CURRENT_USER\Software\Valve\Steam\Apps\440 /f

REM Disable Steam Cloud for TF2
REG ADD HKEY_CURRENT_USER\Software\Valve\Steam\Apps\440 /v Cloud /t REG_DWORD /d "0x0" /f

:exit
ENDLOCAL
EXIT

:loop-notvalid
ECHO.
ECHO That's not a valid reply. Try again.
ECHO.
SET %CHECKCONTINUE%=
GOTO listaction

:loop-noreply
ECHO.
ECHO You must enter a reply.
ECHO.
SET %CHECKCONTINUE%=
GOTO listaction

Antwort1

Erstens haben Sie auf mehreren Zeilen:

SET %CHECKCONTINUE%=

Dies ändert nicht, CHECKCONTINUEsondern verwendet seineWertals Variablenname.

Ändern Sie es in:

SET CHECKCONTINUE=

Es wäre auch besser, wenn Sie es direkt darüber verschieben würden set /p ...– auf diese Weise würden Sie es nur einmal benötigen.


if definednimmt auch nur einen Variablennamen an, also statt

IF DEFINED %CHECKCONTINUE% GOTO loop-notvalid

du solltest benutzen:

IF DEFINED CHECKCONTINUE GOTO loop-notvalid

Gleiches gilt für diese Zeile:

IF NOT DEFINED %CHECKCONTINUE% GOTO loop-noreply

Der Ausdruck kann jedoch folgendermaßen abgekürzt werden:

GOTO loop-noreply

Wenn die Variable definiert wäre, würde die Ausführung diese Zeile sowieso nie erreichen ( if defined ...siehe oben).


So hätte ich es geschrieben:

@echo off & setlocal
title Registry restore script
:: Restores registry settings and disables the Cloud

:menu
echo I'm about to...
echo 1) Remove the registry data that specifies settings for TF2
echo 2) Forcibly disable Steam Cloud.
echo.
set check=
set /p check=Okay to continue? (y/n)
:: /i means case-insensitive comparison
if /i %check%==y goto :start
if /i %check%==yes goto :start
if /i %check%==n goto :EOF
if /i %check%==no goto :EOF
:: On empty response, pick the safest option as default
if not defined check goto :EOF

goto :loop-invalid

:start
:: Delete application specific data
reg delete HKCU\Software\Valve\Source\tf\Settings /f
reg delete HKCU\Software\Valve\Steam\Apps\440 /f

:: Disable Steam Cloud for TF2
reg add HKCU\Software\Valve\Steam\Apps\440 /v Cloud /t REG_DWORD /d "0x0" /f

:loop-invalid
echo.
echo Not a valid answer.
goto :menu

Antwort2

Erweiterung der großartigen Antwort von Grawity:

Um zunächst Ihre Frage zu beantworten: Warum wird das Batch-Skript beendet, wenn %CHECKCONTINUE% ein Nullwert zugewiesen wird?

Das Problem ist, dass Sie in Zeile 16 Folgendes tun:

if %CHECKCONTINUE%==n GOTO exit

Da CHECKCONTINUE„undefiniert“ ist, wird es als „leerer“ String ausgewertet, sodass die Anweisung in Zeile 16 tatsächlich Folgendes bewirkt:

if ==n GOTO exit

Dies ist eine ungültige Anweisung, da sich auf der linken Seite nichts befindet "==". Daher wird das Batch-Skript beendet, wenn es versucht, eine falsch formatierte Anweisung auszuführen:

C:\>script.cmd
I'm about to...
1.) Remove the registry data that specifies settings for TF2
2.) Forcibly disable Steam Cloud.

Okay to continue? (y/n): <ENTER key pressed>
GOTO was unexpected at this time.

C:\>

Ein ähnliches Problem hätten Sie, wenn jemand etwas eintippt, das ein Leerzeichen enthält:

C:\>script.cmd
I'm about to...
1.) Remove the registry data that specifies settings for TF2
2.) Forcibly disable Steam Cloud.

Okay to continue? (y/n): Yes please
please==n was unexpected at this time.

C:\>

Um dies zu beheben, sollten Sie die Begriffe in Anführungszeichen setzen, etwa so:

if "%CHECKCONTINUE%"=="n" GOTO :exit

Dies ist erforderlich, wenn die verwendeten Variablen „leer“ sein könnten oder eingebettete Leerzeichen enthalten könnten. Es ist jedoch einfach eine gute Idee, bei der Auswertung mit immer doppelte Anführungszeichen zu verwenden "==".

Hinweis: Einige Fehler (wie der oben mit "if"und ) "=="sind „schwerwiegende“ Fehler, die dazu führen, dass die Ausführung des Batch-Skripts sofort gestoppt wird. Andere Fehler (wie der unten mit "set") sind „nicht schwerwiegende“ Fehler. Bei „nicht schwerwiegenden“ Fehlern wird die Anweisung mit dem Fehler NICHT ausgeführt, eine Fehlermeldung wird angezeigt und das Batch-Skript wird ab der nächsten Anweisung weiter ausgeführt.

Als nächstes bemerkte Grawity zu dieser Zeile:

set %CHECKCONTINUE%=

Dadurch wird CHECKCONTINUE nicht geändert, sondern dessen Wert als Variablenname verwendet.

Wenn es wiederum CHECKCONTINUE„undefiniert“ wäre, würde es als „leerer“ String ausgewertet, sodass die Anweisung tatsächlich Folgendes bewirkt:

set =

Dies ist auch eine ungültige Aussage, da sich auf der linken Seite nichts befindet "=".

Und diese Zeilen:

if defined %CHECKCONTINUE% GOTO loop-notvalid
if not defined %CHECKCONTINUE% GOTO loop-noreply

"if defined"(und "if not defined") erwartet einen Variablennamen, nicht den Wert einer Variablen. Wenn CHECKCONTINUEnicht definiert wäre, %CHECKCONTINUE%würde es als leere Zeichenfolge ausgewertet und diese Anweisungen wären tatsächlich:

if defined  GOTO loop-notvalid
if not defined  GOTO loop-noreply

Hier prüft "if defined"(und ), ob eine Variable mit dem Namen definiert ist oder nicht."if not defined"GOTO

Außerdem wurde für diese 3 Zeilen CHECKCONTINUEtatsächlich „if“ definiert "set"und würde auf der der Variablen und nicht auf der der Variablen selbst "if defined"operieren . Wenn also bereits ein Wert von vorhanden war , dann:"value""name"CHECKCONTINUE"y"

set %CHECKCONTINUE%=
if defined %CHECKCONTINUE% goto loop-notvalid
if not defined %CHECKCONTINUE% goto loop-noreply

würde eigentlich so gesehen werden:

set y=
if defined y goto loop-notvalid
if not defined y goto loop-noreply

Beispiel „script.cmd“:

@set "CHECKCONTINUE="

@rem ## CHECKCONTINUE="%CHECKCONTINUE%" (undefined/empty). 
@rem ## 05: set %CHECKCONTINUE%=
set %CHECKCONTINUE%=

@echo This doesn't set the value of of the variable named "CHECKCONTINUE". 
@echo Since no variable name is actually specified, it is an error. 



@set "CHECKCONTINUE=yes"
@set "yes=something"

@rem ## CHECKCONTINUE="%CHECKCONTINUE%" and the value of the variable named "yes"="%yes%" 
@rem ## 17: set %CHECKCONTINUE%=
set %CHECKCONTINUE%=

@echo This doesn't set the value of the variable named "CHECKCONTINUE". 
@echo Since CHECKCONTINUE="%CHECKCONTINUE%", it sets the value of the variable named 
@echo "%CHECKCONTINUE%". No error is shown because the statement is valid. 
@echo It could have been a problem (well, at least a big annoyance) if 
@echo CHECKCONTINUE had the value: "path". The statement 
@echo should be: set "CHECKCONTINUE=" 

@rem ## 27: echo CHECKCONTINUE still has the value: "%CHECKCONTINUE%"
@echo CHECKCONTINUE still has the value: "%CHECKCONTINUE%"

@rem ## 30: echo and the variable named "%CHECKCONTINUE%" is now empty="%yes%"
@echo and the variable named "%CHECKCONTINUE%" is now empty="%yes%"



@set "yes="
@set "CHECKCONTINUE="
@set "echo=something"

@rem ## CHECKCONTINUE="%CHECKCONTINUE%" (undefined) and the value of the variable 
@rem ## named "echo"="%echo%". 
@rem ## 41: if defined %CHECKCONTINUE% echo Variable is defined.
if defined %CHECKCONTINUE% echo Variable is defined.

@echo This doesn't check if the variable named "CHECKCONTINUE" is defined. 
@echo Since it's "empty", it is skipped (well, there is nothing there to 
@echo "skip") and "if defined" is checking the next word (which is "echo"). 
@echo What's left is: if defined echo Variable is defined. 
@echo So, it checks if a variable named "echo" is defined (which it is). 
@echo Since "if defined" has checked a variable named "echo", it then tries 
@echo to execute the rest of the line starting with the word "Variable", 
@echo as a command. This fails and is an error. The statement 
@echo should be: if defined CHECKCONTINUE echo Variable is defined. 



@set "echo="

@rem ## CHECKCONTINUE="%CHECKCONTINUE%" (undefined) and "echo"="%echo%" (undefined). 
@rem ## 59: if not defined %CHECKCONTINUE% echo The-variable-is-not-defined.
if not defined %CHECKCONTINUE% echo The-variable-is-not-defined.

@echo Similar: Since "if not defined" has checked a variable named "echo" 
@echo (which is "undefined"), it then tries to execute the rest of the 
@echo line: "The-variable-is-not-defined." as a command. This fails and is 
@echo an error. The statement 
@echo should be: if not defined CHECKCONTINUE echo The-variable-is-not-defined. 



@set "echo=something"

@rem ## CHECKCONTINUE="%CHECKCONTINUE%" (undefined) and "echo"="%echo%". 
@rem ## 73: if defined %CHECKCONTINUE% echo Verify this.
if defined %CHECKCONTINUE% echo Verify this.

@echo Again, similar: Since "if defined" has checked a variable named 
@echo "echo", it then tries to execute the rest of the line starting with 
@echo the word: "Verify" as a command. This happens to be a valid command 
@echo but it also fails because of an incorrect parameter for the command. 
@echo The statement should be: if defined CHECKCONTINUE echo Verify this. 



@set "echo="

@set "CHECKCONTINUE=yes"
@set "yes="

@rem ## CHECKCONTINUE="%CHECKCONTINUE%" and the variable named "yes"="%yes%" (undefined). 
@rem ## 90: if not defined %CHECKCONTINUE% echo CHECKCONTINUE is not defined.
if not defined %CHECKCONTINUE% echo CHECKCONTINUE is not defined.

@echo Here "CHECKCONTINUE" is defined, but "if not defined" still doesn't 
@echo check if the variable named "CHECKCONTINUE" is defined. Since 
@echo CHECKCONTINUE has a value of "%CHECKCONTINUE%", "if not defined" is 
@echo checking if a variable named "%CHECKCONTINUE%" is defined (which it isn't). 
@echo This causes "if not defined" to proceed and echo the message when 
@echo that's probably not what was intended. The statement 
@echo should be: if not defined CHECKCONTINUE echo CHECKCONTINUE is not defined.

Wenn Sie „script.cmd“ ausführen, erhalten Sie:

## CHECKCONTINUE="" (undefined/empty). 
## 05: set %CHECKCONTINUE%=

    C:\>set =
    The syntax of the command is incorrect.

This doesn't set the value of of the variable named "CHECKCONTINUE". 
Since no variable name is actually specified, it is an error. 



## CHECKCONTINUE="yes" and the value of the variable named "yes"="something" 
## 17: set %CHECKCONTINUE%=

    C:\>set yes=

This doesn't set the value of the variable named "CHECKCONTINUE". 
Since CHECKCONTINUE="yes", it sets the value of the variable named 
"yes". No error is shown because the statement is valid. 
It could have been a problem (well, at least a big annoyance) if 
CHECKCONTINUE had the value: "path". The statement 
should be: set "CHECKCONTINUE=" 

## 27: echo CHECKCONTINUE still has the value: "%CHECKCONTINUE%"

    CHECKCONTINUE still has the value: "yes"

## 30: echo and the variable named "yes" is now empty="%yes%"

    and the variable named "yes" is now empty=""



## CHECKCONTINUE="" (undefined) and the value of the variable 
## named "echo"="something". 
## 41: if defined %CHECKCONTINUE% echo Variable is defined.

    C:\>if defined echo Variable is defined.
    'Variable' is not recognized as an internal or external command,
    operable program or batch file.

This doesn't check if the variable named "CHECKCONTINUE" is defined. 
Since it's "empty", it is skipped (well, there is nothing there to 
"skip") and "if defined" is checking the next word (which is "echo"). 
What's left is: if defined echo Variable is defined. 
So, it checks if a variable named "echo" is defined (which it is). 
Since "if defined" has checked a variable named "echo", it then tries 
to execute the rest of the line starting with the word "Variable", 
as a command. This fails and is an error. The statement 
should be: if defined CHECKCONTINUE echo Variable is defined. 



## CHECKCONTINUE="" (undefined) and "echo"="" (undefined). 
## 59: if not defined %CHECKCONTINUE% echo The-variable-is-not-defined.

    C:\>if not defined echo The-variable-is-not-defined.
    'The-variable-is-not-defined.' is not recognized as an internal or external command,
    operable program or batch file.

Similar: Since "if not defined" has checked a variable named "echo" 
(which is "undefined"), it then tries to execute the rest of the 
line: "The-variable-is-not-defined." as a command. This fails and is 
an error. The statement 
should be: if not defined CHECKCONTINUE echo The-variable-is-not-defined. 



## CHECKCONTINUE="" (undefined) and "echo"="something". 
## 73: if defined %CHECKCONTINUE% echo Verify this.

    C:\>if defined echo Verify this.
    An incorrect parameter was
    entered for the command.

Again, similar: Since "if defined" has checked a variable named 
"echo", it then tries to execute the rest of the line starting with 
the word: "Verify" as a command. This happens to be a valid command 
but it also fails because of an incorrect parameter for the command. 
The statement should be: if defined CHECKCONTINUE echo Verify this. 



## CHECKCONTINUE="yes" and the variable named "yes"="" (undefined). 
## 90: if not defined %CHECKCONTINUE% echo CHECKCONTINUE is not defined.

    C:\>if not defined yes echo CHECKCONTINUE is not defined.
    CHECKCONTINUE is not defined.

Here "CHECKCONTINUE" is defined, but "if not defined" still doesn't 
check if the variable named "CHECKCONTINUE" is defined. Since 
CHECKCONTINUE has a value of "yes", "if not defined" is 
checking if a variable named "yes" is defined (which it isn't). 
This causes "if not defined" to proceed and echo the message when 
that's probably not what was intended. The statement 
should be: if not defined CHECKCONTINUE echo CHECKCONTINUE is not defined.

Alternativ zu "set /p"können Sie auch Folgendes verwenden "choice":

@echo off
title Registry restore script
rem Restores registry settings and disables the cloud

rem "quotes" around variable name and value for set visibly shows what 
rem the variable is being set to and prevents accidentally including  
rem trailing whitespace in the variable's value.
    set "CHECKCONTINUE="

:listaction
echo I'm about to...
echo 1.) Remove the registry data that specifies settings for TF2
echo 2.) Forcibly disable Steam Cloud.
echo.
choice /c yn /M "Okay to continue"

set "CHECKCONTINUE=%errorlevel%"
if %CHECKCONTINUE% EQU 1 @echo Pressed Y && goto :start
if %CHECKCONTINUE% EQU 2 @echo Pressed N && goto :exit
if %CHECKCONTINUE% EQU 0 @echo Pressed Ctrl-C+n
@echo.

@echo Terminate batch job cancelled. You must enter a reply. Press n to exit.
@echo.
goto :listaction

rem The remainder of your code goes here ...

Hinweis: Der Code bei der Bezeichnung: "loop-notvalid"ist nicht erforderlich, da „Auswahl“ keine undefinierten Antworten (j/n) akzeptiert.

Außerdem ist die einzige Möglichkeit, eine „leere“ Antwort vom Befehl „choice“ zu erhalten, wenn der Benutzer „Strg-C“ drückt, um den Batch-Job zu beenden, und dann N (Nein) in die Eingabeaufforderung „Batch-Job beenden (J/N)?“ eingibt, um anzuzeigen, dass er NICHT beenden möchte. Der obige Code fängt dies ab, druckt eine Meldung aus und springt (goto) dann zum Label „:listaction“, um den Benutzer erneut zu fragen, sodass Sie den Code auch beim Label „loop-noreply“ nicht benötigen.

Es ist nicht nötig, den Fehlerlevel „zurückzusetzen“, da dies der Auswahlbefehl übernimmt. Und es ist nicht notwendig, die CHECKCONTINUEVariable zu löschen, da sie immer gleich gesetzt wird, %errorlevel%bevor der Wert von CHECKCONTINUEgeprüft wird.

Standardmäßig ist „choice“ „case-insensitive“, das Drücken von „Y“ oder „N“ ist also dasselbe wie das Drücken von „y“ oder „n“. Dieses Verhalten kann durch Angabe /csin der Befehlszeile geändert werden.

verwandte Informationen