Warum funktioniert der choice Befehl für batch nicht wie er soll?
Ich habe vor kurzem angefangen mich mit batch auseinander zu setzen. Ich wollte nun mit dem if Befehl arbeiten und habe mir gedacht ein kleines Programm mit Input zu gestalten.
- @echo off
- :top
- if [%$ecbId%] == [] (
- echo Enter 1 for ...
- echo Enter 2 for ...
- set /p choice="Type input: "
- if "%choice%"=="1" (
- echo 1
- timeout 3
- )
- if "%choice%"=="2" (
- echo 2
- timeout 3
- )
- )
- goto top
Wenn ich nun 1 eingebe, springt das Programm direkt zum Anfang zurück. Danach kann ich irgendetwas eingeben und das Programm führt das aus, was es bei 1 ausführen soll. Wenn ich 2 eingebe ist es wieder das Gleiche. Ich kann den Fehler einfach nicht finden und bin so langsam am Verzweifeln.
2 Antworten
kleine Unterrichtsstunde gefällig?🧐🤫
...oder geh zum Ende meiner Antwort, da steht was Wichtiges...Batch ist im eine uralte äußerlich sehr simpel gestrickte Stapelverarbeitung.
ein Stapel von Kommandos schön zeilenweise
wird abgearbeitet. Nicht verwunderlich das die Auswertung einer frisch gesetzten Variable erst ab der nächsten Zeile erwartet wird.
set "Var=blubb"
echo %var%
Das klappt wie erwartet, die Variable wird in der nächsten Zeile abgerufen.
Jetzt kommt der Kasus Knacksus : Alle Befehle innerhalb eine Klammerblocks werden vom Kommandointerpreter als eine Zusammenhängende Zeile ausgewertet.
(
set "Var=blubb"
echo abgerufen innerhal des gleichen Klammeblocks: %var%
)
echo abgerufen ausserhalb Klammeblocks: %var%
Da die variable vor dem setzen in der Klammer keinen Wert hatte ist nichts zum abrufen da. Es kommt noch schlimmer. Wenn die Variable vor dem setzen bereits eien anderen Wert als den in den Klammern gesetzten Wert hatte kann auch das Ergebnis eines Vergleichs völlig falsch sein:
set "Var=0"
if "%Var%"=="0" (
set "Var=1"
if "%Var%"=="1" goto :label1
)
echo da ging was schief...
pause
exit /b
:label1
echo hier sollte ich ankommen
pause
Klammerblöcke haben noch andere Tücken, das ist jedoch hier irrelevent. Fast Dein gesamtes Script ist Quasi eine Zeile... darin sind alle gesetzten Variablen tot. Hätten aber nach dem Sprung zu :top den in vorherigen Runde eingegebenen Wert. (lass mal schön das Echo off am Anfang weg, dann siehst Du was die aufgelösten Variablen enthalten!
Wie kommst Du am billigsten aus der Misere heraus? ...in diesem simplen Fall den Klammeblock loswerden.
demo1.cmd
:top
rem negative Logik... überspringe das Menü wenn %$ecbId% nicht Leer ist.
if "%$ecbId%" neq "" goto :fragNicht
echo Enter 1 for ...
echo Enter 2 for ...
set /p choice="Type input: "
if "%choice%"=="1" (
echo 1
timeout 3
)
if "%choice%"=="2" (
echo 2
timeout 3
)
:fragNicht
goto top
Das läuft wie es soll.
Dein Menü ist Mist, da der Nutzer auch etwas völlig blödes eingaben kann. Erlaube einem Nutzer nur Eingaben auf welche Dein Programm möglichst einfach reagieren kann. der Choice-Befehl reagiert nur auf die vorgegebenen Zahlen/Buchstaben.
echtesChoiceMenu.cmd
@echo off
chcp 65001 >nul
echo [1]Irgendwas [2]Was anderes
echo [X] Programm beenden
:ask
choice /c 12x /m "Wähle:"
if %errorlevel% equ 1 (
echo Irgendwas gewählt
timeout 3 >nul
goto :ask
)
if %errorlevel% equ 2 (
echo Was anderes gewählt
timeout 3 >nul
goto :ask
)
rem da nur noch die 3.Option übrig ist und die anderen Beiden wegspringen Du Dir einen weiteren Vergleich sparen
echo winke...Winke...
timeout 5 >nul
Sollte es unumgänglich sein verschachtelte Variablenzugriffe innerhalb eines Klammerblocks auszuführen, ist di einfachste Option die verzögerte Variablenexpansion:
demo3.cmd
@echo off
chcp 65001 >nul
setlocal enableDelayedExpansion
echo [1]Irgendwas [2]Was anderes
echo [X] Programm beenden
:ask
rem !!!!Achtung innerhalb eines Klammerblocks sind keine Sprünge möglich!!!!!
rem ein :label kann eine Batch crashen . ein goto zu einem Label außerhalb der Klmmern ist jedoch möglich
if irgendwas==irgendwas (
choice /c 12x /m "Wähle:"
if !errorlevel! equ 1 (
echo Irgendwas gewählt
timeout 3 >nul
goto :ask
)
if !errorlevel! equ 2 (
echo Was anderes gewählt
timeout 3 >nul
goto :ask
)
echo winke...Winke...
timeout 5 >nul
exit /b
)
echo irgendwelches zeug wen irgendwas nicht irgendwas ist
pause
... setlocal enableDelayedExpansion ist aber kein Allheilmittel. Das bringt neue Probleme mit sich....
- https://ss64.com/nt/delayedexpansion.html
- https://ss64.com/nt/choice.html
- https://ss64.com/nt/syntax-brackets.html
Batch ein Flickenteppich von Regeln, Ausnahmen von Regeln, Ausnahmen von den Ausnahmen, usw. Viele Anfänger fallen auf die simple Basissyntax herein. Wenn sie auf den Geschmack am Programmieren gekommen sind und etwas mehr als Spagetticode produzieren wollen, schlägt das Monster zu.
...und man muss schon echt viel Langeweile haben um sich Batch in all seinen Fasetten anzutun und Batch kann echt fies werden: https://www.gutefrage.net/frage/csv-daten-in-batch-anzeigen#answer-451313130
Vergiss Batch... Powershell ist viel angenehmer.Hui. Also:
- Das ist NICHT der Choice Befehl. DAS und DAS ist der Choice Befehl.
- Du fragst nach einer Eingabe des Nutzers um eine Variable festzulegen. Mit dem Choice Befehl fragst du nach einer Eingabe eines einzelnen Buchstabens/einer einzigen Zahl, und untersuchst dann den Errorlevel. Lies dir dazu mal dies durch.
- Bei "if "%choice%"=="1" (" Z.7 musst du die " Dinger bei den = Zeichen und bei der 1 weglassen. Gleiches gilt für das 2.
PS: Mit "cls" kannst du den Bildschirm löschen, damit du nicht immer mehr Zeilen hast sondern sich immer wieder neu aufbauende "Seiten".
Viel Glück!
Wenn du den 3. Punkt berücksichtigst sollte es schon funktionieren. Alternativ kannst du natürlich auch den richtigen Choice Befehl verwenden. :)
Du musst die Gänsefüßchen übrigens ebenso bei "Choice" entfernen, und auch bei "Type Input"!