Wie überprüfe ich den Befehlszeilenparameter in der Datei ".bat"?

101

Mein Betriebssystem ist Windows Vista. Ich benötige eine ".bat" -Datei, in der ich überprüfen muss, ob der Benutzer einen Befehlszeilenparameter eingibt oder nicht. Wenn dies der Fall ist, wenn der Parameter gleich ist, -bwerde ich etwas tun, andernfalls werde ich "Ungültige Eingabe" markieren. Wenn der Benutzer keinen Befehlszeilenparameter eingibt, werde ich etwas tun. Ich habe folgende .bat-Datei erstellt. Es funktioniert für Fälle -bund ist nicht gleich -b- aber es schlägt fehl, wenn der Benutzer keinen Befehlszeilenparameter übergibt.

Ich bekomme immer Fehler:

GOTO was unexpected at this time.

Kann mir jemand sagen, was ich hier falsch mache?


ECHO OFF
CLS
ECHO.

IF [%1]==[/?] GOTO BLANK

IF %1=="-b" GOTO SPECIFIC

IF NOT %1=="-b" GOTO UNKNOWN

:SPECIFIC

ECHO SPECIFIC

GOTO DONE

:BLANK

ECHO No Parameter

GOTO DONE

:UNKNOWN

ECHO Unknown Option

GOTO DONE

:DONE

ECHO Done!
javauser71
quelle
Wenn Sie GOTO BLANKden beiden anderen IFAnweisungen Klammern (wie in der Zeile) hinzufügen , wird das Problem dadurch behoben?
Jeremiah Willcock

Antworten:

140

Sie müssen überprüfen, ob der Parameter leer ist: if "%~1"=="" goto blank

Sobald Sie das getan haben, schalten Sie -b ein / ein: if "%~1"=="-b" (goto specific) else goto unknown

Das Umgeben der Parameter mit Anführungszeichen erleichtert das Überprüfen auf leere / leere / fehlende Parameter. "~" stellt sicher, dass doppelte Anführungszeichen entfernt werden, wenn sie sich im Befehlszeilenargument befinden.

afrazier
quelle
Das funktioniert!! Nur "else" wird nicht akzeptiert. Ich erhalte die Fehlermeldung: 'else' wird nicht als interner oder externer Befehl, bedienbares Programm oder Batchdatei erkannt. Also habe ich eine weitere IF für den Fall "ungleich -b" hinzugefügt. Danke für die schnelle Antwort.
javauser71
7
Die ELSE müssen auf der gleichen Linie wie die IF sein, oder es muss direkt nach einer Klammer sein
jeb
4
Dies scheint für mich nicht zu funktionieren, wenn% 1 Leerzeichen enthält. Dies kann der Fall sein, wenn es sich um den vollständigen Pfad zu einer ausführbaren Datei handelt. In Jeremiah Willcocks Antwort finden Sie eine Lösung, die auch für Parameter mit Leerzeichen in ihren Werten funktioniert.
Mark A. Fitzgerald
Es wird nicht akzeptiert, wenn Ihr Argument a ist File. In diesem Fall sollten Sie nur existoder prüfen not exist. Aus diesem Grund sollten Ihre Argumente gut definiert sein oder einfach Powershell oder VbScript verwenden (wenn Sie in den
1
Dies schlägt fehl für run.bat "a b". "%1"==""stürzt ab, wenn das Argument ein Leerzeichen hat. Siehe stackoverflow.com/a/46942471
wisbucky
27

Eine Antwort finden Sie unter http://ss64.com/nt/if.html . Der Befehl ist IF [%1]==[] GOTO NO_ARGUMENToder ähnlich.

Jeremiah Willcock
quelle
1
Das funktioniert nicht nur! Es funktioniert einfach im Gegensatz zu "%1"=="". Darauf muss ich in meiner eigenen Antwort näher eingehen.
Tomasz Gandor
1
Dies wird unterbrochen, wenn% 1 in Anführungszeichen gesetzt wird, z foo.bat "1st parameter" 2nd_param. Siehe stackoverflow.com/questions/2541767/…
matt wilkie
Die Verwendung [%1]==[-b]stimmt nicht überein, wenn arg in Anführungszeichen steht. Beispiel run.bat "-b". Siehe stackoverflow.com/a/46942471
wisbucky
20

Die kurze Antwort - verwenden Sie eckige Klammern:

if [%1]==[] goto :blank

oder (wenn Sie mit zitierten Argumenten umgehen müssen, siehe Bearbeiten unten):

if [%~1]==[] goto :blank

Warum? du könntest fragen. Nun, genau wie Jeremiah Willcock es erwähnt hat: http://ss64.com/nt/if.html - das benutzen sie! OK, aber was ist los mit den Zitaten?

Nochmals kurze Antwort: Sie sind "magisch" - manchmal werden doppelte (doppelte) Anführungszeichen in einfache (doppelte) Anführungszeichen umgewandelt. Und sie müssen zunächst einmal zusammenpassen.

Betrachten Sie dieses kleine Skript:

@rem argq.bat
@echo off

:loop 
if "%1"=="" goto :done
echo %1
shift
goto :loop

:done
echo Done.

Testen wir es:

C:\> argq bla bla
bla
bla
Done.

Scheint zu funktionieren. Aber jetzt schalten wir in den zweiten Gang:

C:\> argq "bla bla"
bla""=="" was unexpected at this time.

Boom Dies wurde weder als wahr noch als falsch bewertet. Das Skript starb. Wenn Sie den Reaktor irgendwo auf der ganzen Linie ausschalten sollten, dann haben Sie Pech. Du wirst jetzt wie Harry Daghlian sterben.

Sie denken vielleicht - OK, die Argumente dürfen keine Anführungszeichen enthalten. Wenn ja, passiert dies. Falsch Hier ist ein Trost:

C:\> argq ""bla bla""
""bla
bla""
Done.

Oh ja. Keine Sorge - manchmal dies wird funktionieren.

Versuchen wir es mit einem anderen Skript:

@rem args.bat
@echo off

:loop 
if [%1]==[] goto :done
echo %1
shift
goto :loop

:done
echo Done.

Sie können selbst testen, ob es in den oben genannten Fällen in Ordnung ist. Dies ist logisch - Anführungszeichen haben nichts mit Klammern zu tun, daher gibt es hier keine Magie. Aber was ist mit dem Aufpeppen der Argumente mit Klammern?

D:\>args ]bla bla[
]bla
bla[
Done.

D:\>args [bla bla]
[bla
bla]
Done.

Kein Glück da. Die Klammern können den cmd.exeParser einfach nicht ersticken .

Kehren wir für einen Moment zu den bösen Zitaten zurück. Das Problem war da, als das Argument mit einem Zitat endete:

D:\>argq "bla1 bla2"
bla2""=="" was unexpected at this time.

Was ist, wenn ich nur passiere:

D:\>argq bla2"
The syntax of the command is incorrect.

Das Skript wird überhaupt nicht ausgeführt. Gleiches gilt für args.bat:

D:\>args bla2"
The syntax of the command is incorrect.

Aber was bekomme ich "in einem solchen Fall , wenn die Anzahl der Zeichen "übereinstimmt" (dh - gerade ist):

D:\>args bla2" "bla3
bla2" "bla3
Done.

NICE - Ich hoffe, Sie haben etwas darüber gelernt, wie .batDateien ihre Befehlszeilenargumente aufteilen (TIPP: * Es ist nicht genau wie in Bash). Das obige Argument enthält ein Leerzeichen. Die Anführungszeichen werden jedoch nicht automatisch entfernt.

Und argq? Wie reagiert es darauf? Vorhersehbar:

D:\>argq bla2" "bla3
"bla3"=="" was unexpected at this time.

Denken Sie also nach, bevor Sie sagen: "Wissen Sie was? Verwenden Sie einfach Anführungszeichen. [Für mich sieht das besser aus]".

Bearbeiten

Vor kurzem gab es Kommentare zu dieser Antwort - nun, quadratische Klammern können nicht damit umgehen, zitierte Argumente zu übergeben und sie so zu behandeln, als wären sie nicht zitiert.

Die Syntax:

if "%~1"=="" (...)

Ist keine neu gefundene Tugend der doppelten Anführungszeichen, sondern eine Anzeige eines ordentlichen Merkmals zum Entfernen von Anführungszeichen aus der Argumentvariablen, wenn das erste und letzte Zeichen ein doppeltes Anführungszeichen ist.

Diese "Technologie" funktioniert genauso gut mit eckigen Klammern:

if [%~1]==[] (...)

Es war nützlich, darauf hinzuweisen, deshalb stimme ich auch der neuen Antwort zu.

Schließlich, Fans von doppelten Zitaten, gibt ""es in Ihrem Buch ein Argument für das Formular , oder ist es leer? Frage nur' ;)

Tomasz Gandor
quelle
1
Eckige Klammern [%1]==[-b]stimmen nicht überein, wenn arg wie folgt zitiert wird run.bat "-b". Siehe stackoverflow.com/a/46942471
wisbucky
Historischer Hinweis: [%1]==[-b]und "%1"=="-b"waren die gleichen für Batch-Skripte von Win 98 und früheren MS / PC-DOS-Systemen. Seit Win 2000 / NT wurde eine Syntax eingeführt, if "%~1"=="-b"bei der doppelte Anführungszeichen eine besondere Bedeutung haben. So sollten Sie Skripte codieren, da sie einen robusteren Schutz bieten. Doppelte Anführungszeichen entziehen sich der Bedeutung von Sonderzeichen (versuchen Sie & | und% Zeichen in Ihrer Befehlszeile). 99,9% der Beispiele arbeiten mit doppelter Anführungszeichen - Ihr Beispiel argq bla2" "bla3dient nur zur Rechtfertigung eckiger Klammern. Eingebettete doppelte Anführungszeichen sind ein Rezept für eine Katastrophe - sagen Sie einfach
Skip R
@SkipR - Aus diesem Grund können diese Sonderzeichen in Windows-Dateisystemen nicht in Namen enthalten sein. Ich habe keinen mathematischen Beweis, aber ich denke, dass einfach NICHT alles in der cmdShell zitiert werden kann (im Sinne von - wörtlich gemacht durch eine Escape-Sequenz usw.) . In anderen Systemen können Sie manchmal alles zitieren, einschließlich NUL-Zeichen. ( stackoverflow.com/questions/2730732/… ) - Diese Frage zeigt nur, dass Sie ein externes Programm verwenden müssen.
Tomasz Gandor
8

Zusätzlich zu den anderen Antworten, die ich abonniere, können Sie den /ISchalter des IFBefehls verwenden.

... der / I-Schalter, falls angegeben, sagt, dass Zeichenfolgenvergleiche ohne Berücksichtigung der Groß- und Kleinschreibung durchgeführt werden sollen.

Dies kann hilfreich sein, wenn Sie Ihren Benutzern die Flexibilität geben möchten, die Parameter unabhängig von Groß- und Kleinschreibung zu berücksichtigen.

IF /I "%1"=="-b" GOTO SPECIFIC
PA.
quelle
5

Sie vergleichen Zeichenfolgen. Wenn ein Argument weggelassen wird, wird es %1zu einem Leerzeichen erweitert, sodass die Befehle IF =="-b" GOTO SPECIFICbeispielsweise (was ein Syntaxfehler ist) werden. Wickeln Sie Ihre Zeichenfolgen in Anführungszeichen (oder eckige Klammern).

REM this is ok
IF [%1]==[/?] GOTO BLANK

REM I'd recommend using quotes exclusively
IF "%1"=="-b" GOTO SPECIFIC

IF NOT "%1"=="-b" GOTO UNKNOWN
Jeff Mercado
quelle
WENN [% 1] == [/?] Nicht funktioniert, aber wenn ich IF [% 1] == [] oder "% 1" == "" mache, dann funktioniert es. Jedenfalls kann ich jetzt loslegen. Danke für die schnelle Antwort.
javauser71
5

Eigentlich haben alle anderen Antworten Mängel. Der zuverlässigste Weg ist:

IF "%~1"=="-b" (GOTO SPECIFIC) ELSE (GOTO UNKNOWN)

Ausführliche Erklärung:

Die Verwendung von "%1"=="-b"wird zum Absturz bringen, wenn Argumente mit Leerzeichen und Anführungszeichen übergeben werden. Dies ist die am wenigsten zuverlässige Methode.

IF "%1"=="-b" (GOTO SPECIFIC) ELSE (GOTO UNKNOWN)

C:\> run.bat "a b"

b""=="-b" was unexpected at this time.

Die Verwendung [%1]==[-b]ist besser, da sie nicht mit Leerzeichen und Anführungszeichen abstürzt, aber nicht übereinstimmt, wenn das Argument von Anführungszeichen umgeben ist.

IF [%1]==[-b] (GOTO SPECIFIC) ELSE (GOTO UNKNOWN)

C:\> run.bat "-b"

(does not match, and jumps to UNKNOWN instead of SPECIFIC)

Die Verwendung "%~1"=="-b"ist am zuverlässigsten. %~1entfernt umgebende Anführungszeichen, wenn sie existieren. Es funktioniert also mit und ohne Anführungszeichen und auch ohne Argumente.

IF "%~1"=="-b" (GOTO SPECIFIC) ELSE (GOTO UNKNOWN)

C:\> run.bat
C:\> run.bat -b
C:\> run.bat "-b"
C:\> run.bat "a b"

(all of the above tests work correctly)
wisbucky
quelle
1
Dies ist nicht das Ende von eckigen Klammern, sehen Sie: IF [%~1]==[]- das funktioniert und es funktioniert sogar "-b". Sie müssen nur in der Lage sein, in der Box zu denken , ähm, quadratisch [Klammern].
Tomasz Gandor
2

Ich habe in letzter Zeit Probleme mit der Implementierung komplexer Parameterschalter in einer Batch-Datei. Hier ist das Ergebnis meiner Forschung. Keine der angegebenen Antworten ist völlig sicher, Beispiele:

"%1"=="-?" stimmt nicht überein, wenn der Parameter in Anführungszeichen steht (wird für Dateinamen usw. benötigt) oder stürzt ab, wenn der Parameter in Anführungszeichen steht und Leerzeichen enthält (wiederum häufig in Dateinamen)

@ECHO OFF
SETLOCAL
echo.
echo starting parameter test...
echo.
rem echo First parameter is %1
if "%1"=="-?" (echo Condition is true, param=%1) else (echo Condition is false, param=%1)
C:\>test.bat -?

starting parameter test...

Condition is true, param=-?

C:\>test.bat "-?"

starting parameter test...

Condition is false, param="-?"

Jede Kombination mit eckigen Klammern [%1]==[-?]oder [%~1]==[-?]schlägt fehl, wenn der Parameter Leerzeichen in Anführungszeichen enthält:

@ECHO OFF
SETLOCAL 
echo.
echo starting parameter test...
echo.
echo First parameter is %1
if [%~1]==[-?] (echo Condition is true, param=%1) else (echo Condition is false, param=%1)

C:\>test.bat "long file name"

starting parameter test...

First parameter is "long file name"
file was unexpected at this time.

Die vorgeschlagene sicherste Lösung "%~1"=="-?"stürzt mit einem komplexen Parameter ab, der Text außerhalb der Anführungszeichen und Text mit Leerzeichen innerhalb der Anführungszeichen enthält:

@ECHO OFF
SETLOCAL 
echo.
echo starting parameter test...
echo.
echo First parameter is %1
if "%~1"=="-?" (echo Condition is true, param=%1) else (echo Condition is false, param=%1)

C:\>test.bat -source:"long file name"

starting parameter test...

First parameter is -source:"long file name"
file was unexpected at this time.

Die einzige Möglichkeit, um sicherzustellen, dass alle oben genannten Szenarien abgedeckt sind, besteht darin, EnableDelayedExpansion zu verwenden und die Parameter mithilfe von Variablen als Referenz (nicht nach Wert) zu übergeben. Dann funktioniert auch das komplexeste Szenario einwandfrei:

@ECHO OFF
SETLOCAL EnableDelayedExpansion
echo.
echo starting parameter test...
echo.
echo First parameter is %1
:: we assign the parameter to a variable to pass by reference with delayed expansion
set "var1=%~1"
echo var1 is !var1!
:: we assign the value to compare with to a second variable to pass by reference with delayed expansion
set "var2=-source:"c:\app images"\image.png"
echo var2 is !var2!
if "!var1!"=="!var2!" (echo Condition is true, param=!var1!) else (echo Condition is false, param=!var1!)
C:\>test.bat -source:"c:\app images"\image.png

starting parameter test...

First parameter is -source:"c:\app images"\image.png
var1 is -source:"c:\app images"\image.png
var2 is -source:"c:\app images"\image.png
Condition is true, param=-source:"c:\app images"\image.png

C:\>test.bat -source:"c:\app images"\image1.png

starting parameter test...

First parameter is -source:"c:\app images"\image1.png
var1 is -source:"c:\app images"\image1.png
var2 is -source:"c:\app images"\image.png
Condition is false, param=-source:"c:\app images"\image1.png

C:\>test.bat -source:"c:\app images\image.png"

starting parameter test...

First parameter is -source:"c:\app images\image.png"
var1 is -source:"c:\app images\image.png"
var2 is -source:"c:\app images"\image.png
Condition is false, param=-source:"c:\app images\image.png"
D. Barv
quelle
0

Windows Batch hat dazu das Schlüsselwort DEFINED.

IF DEFINED %~1 foo
IF NOT DEFINED %~1 bar
Charles
quelle
Danke David. Ich weiß nicht, warum es keinen Wagenrücklauf und keine neue Leitung zwischen IF und IF NOT gab. Ich habe es nicht einmal bemerkt.
Charles