Comment vérifier le paramètre de ligne de commande dans le fichier «.bat»?

103

Mon système d'exploitation est Windows Vista. J'ai besoin d'un fichier ".bat" où je dois vérifier si l'utilisateur entre un paramètre de ligne de commande ou non. Si c'est le cas, si le paramètre est égal à -balors je ferai quelque chose, sinon je marquerai "Entrée invalide". Si l'utilisateur n'entre aucun paramètre de ligne de commande, je ferai quelque chose. J'ai créé le fichier .bat suivant. Cela fonctionne pour -bet n'est pas égal aux -bcas - mais il échoue lorsque l'utilisateur ne passe aucun paramètre de ligne de commande.

J'obtiens toujours une erreur:

GOTO was unexpected at this time.

Quelqu'un peut-il me dire ce que je fais de mal ici?


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
la source
Si vous ajoutez des crochets (comme dans la GOTO BLANKligne) aux deux autres IFinstructions, est-ce que cela résout le problème?
Jeremiah Willcock le

Réponses:

141

Vous devez vérifier que le paramètre est vide: if "%~1"=="" goto blank

Une fois que vous avez fait cela, faites un commutateur if / else sur -b: if "%~1"=="-b" (goto specific) else goto unknown

Entourer les paramètres de guillemets, il est plus facile de vérifier des éléments tels que des paramètres vides / vides / manquants. "~" garantit que les guillemets doubles sont supprimés s'ils étaient sur l'argument de ligne de commande.

afrazier
la source
Cela marche!! Seul «autre» n'est pas accepté. J'obtiens une erreur: «else» n'est pas reconnu comme une commande interne ou externe, un programme utilisable ou un fichier de commandes. J'ai donc ajouté un autre IF pour le cas "différent de -b". Merci pour la réponse rapide.
javauser71
7
L'ELSE doit être sur la même ligne que l'IF, ou il doit être directement après une parenthèse
jeb
4
Cela ne semble pas fonctionner pour moi si% 1 contient des espaces, ce qui peut être le cas s'il s'agit du chemin complet vers un exécutable. Voir la réponse de Jeremiah Willcock pour une solution qui fonctionne même pour les paramètres avec des espaces dans leurs valeurs.
Mark A. Fitzgerald
il ne sera pas accepté si votre argument est a File, dans ce cas, vous devriez vérifier uniquement existou not exist. C'est pourquoi vos arguments doivent être bien définis, ou simplement utiliser PowerShell ou vbScript (si vous êtes dans les années 80 ..)
1
Cela échoue run.bat "a b". "%1"==""plante si l'argument a un espace. Voir stackoverflow.com/a/46942471
wisbucky
27

Regardez http://ss64.com/nt/if.html pour une réponse; la commande est IF [%1]==[] GOTO NO_ARGUMENTou similaire.

Jérémie Willcock
la source
1
Non seulement cela fonctionne AUSSI! Cela fonctionne juste, contrairement à "%1"=="". Je dois développer cela dans ma propre réponse.
Tomasz Gandor
1
cela s'arrêtera lorsque% 1 est cité, par exemple foo.bat "1st parameter" 2nd_param. Voir stackoverflow.com/questions/2541767/…
matt wilkie
L'utilisation [%1]==[-b]ne correspondra pas si arg est cité. Exemple run.bat "-b". Voir stackoverflow.com/a/46942471
wisbucky
20

La réponse courte - utilisez des crochets:

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

ou (lorsque vous avez besoin de gérer des arguments entre guillemets, consultez la modification ci-dessous):

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

Pourquoi? vous pourriez demander. Eh bien, tout comme Jeremiah Willcock l'a mentionné: http://ss64.com/nt/if.html - ils l'utilisent! OK, mais quel est le problème avec les citations?

Encore une fois, réponse courte: ils sont "magiques" - parfois les guillemets doubles (doubles) sont convertis en guillemets simples (doubles). Et ils doivent correspondre, pour commencer.

Considérez ce petit script:

@rem argq.bat
@echo off

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

:done
echo Done.

Testons-le:

C:\> argq bla bla
bla
bla
Done.

Semble fonctionner. Mais maintenant, passons à la deuxième vitesse:

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

Boom Cela n'a pas évalué à vrai, ni à faux. Le script est mort. Si vous étiez censé éteindre le réacteur quelque part sur la ligne, eh bien - pas de chance. Vous allez maintenant mourir comme Harry Daghlian.

Vous pensez peut-être - OK, les arguments ne peuvent pas contenir de guillemets. S'ils le font, cela se produit. Faux Voici une consolation:

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

Oh oui. Ne vous inquiétez pas - parfois cela va fonctionner.

Essayons un autre script:

@rem args.bat
@echo off

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

:done
echo Done.

Vous pouvez vous tester, que cela fonctionne bien pour les cas ci-dessus. C'est logique - les guillemets n'ont rien à voir avec les crochets, il n'y a donc pas de magie ici. Mais qu'en est-il de pimenter les arguments avec des crochets?

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

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

Pas de chance là-bas. Les parenthèses ne peuvent tout simplement pas étouffer cmd.exel'analyseur.

Revenons un instant aux mauvaises citations. Le problème était là, lorsque l'argument s'est terminé par une citation:

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

Et si je passe juste:

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

Le script ne fonctionnera pas du tout. Idem pour args.bat:

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

Mais qu'est-ce que j'obtiens, lorsque le nombre de "caractères "correspond" (c'est-à-dire - est pair), dans un tel cas:

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

NICE - J'espère que vous avez appris quelque chose sur la façon dont les .batfichiers divisent leurs arguments de ligne de commande (ASTUCE: * Ce n'est pas exactement comme dans bash). L'argument ci-dessus contient un espace. Mais les citations ne sont pas supprimées automatiquement.

Et argq? Comment réagit-il à cela? De manière prévisible:

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

Alors - réfléchissez avant de dire: "Tu sais quoi? Utilise juste des guillemets. [Parce que, pour moi, ça a l'air plus joli]".

Éditer

Récemment, il y a eu des commentaires sur cette réponse - eh bien, les crochets "ne peuvent pas gérer" en passant des arguments cités et en les traitant comme s'ils n'étaient pas cités.

La syntaxe:

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

N'est-ce pas une vertu nouvellement trouvée des guillemets doubles, mais un affichage d'une fonctionnalité intéressante de suppression des guillemets de la variable d'argument, si le premier et le dernier caractère sont des guillemets doubles.

Cette "technologie" fonctionne aussi bien avec les crochets:

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

C'était une chose utile de le souligner, alors je suis également favorable à la nouvelle réponse.

Enfin, fans des guillemets doubles, un argument de forme ""existe-t-il dans votre livre ou est-il vide? Je demandais juste' ;)

Tomasz Gandor
la source
1
Les crochets [%1]==[-b]ne correspondent pas si arg est cité comme run.bat "-b". Voir stackoverflow.com/a/46942471
wisbucky
Remarque historique: [%1]==[-b]et "%1"=="-b"étaient les mêmes pour win 98 et les scripts batch des systèmes MS / PC-DOS antérieurs. Depuis que win 2000 / NT a introduit une syntaxe if "%~1"=="-b"où les guillemets doubles ont une signification spéciale, c'est ainsi que vous devez coder les scripts car elle offre une protection plus robuste. Les guillemets doubles échappent à la signification des caractères spéciaux (essayez & | et% chars dans votre ligne de commande). 99,9% des exemples fonctionnent avec la syntaxe des guillemets doubles - votre exemple argq bla2" "bla3n'est que la casse pour justifier les crochets. Les guillemets doubles intégrés sont une recette pour le désastre - il suffit de dire
Passer R
@SkipR - c'est pourquoi dans les systèmes de fichiers Windows, vous ne pouvez pas avoir ces caractères spéciaux dans les noms. Je n'ai pas de preuve mathématique, mais je pense que tout simplement PAS tout peut être cité (dans le sens de - rendu textuel via une séquence d'échappement, etc.) dans le cmdshell. Dans d'autres systèmes, vous pouvez parfois tout citer, caractère NUL inclus. ( stackoverflow.com/questions/2730732/… ) - cette question montre juste que vous devez utiliser un programme externe.
Tomasz Gandor
8

En plus des autres réponses, auxquelles je souscris, vous pouvez envisager d'utiliser le /Icommutateur de la IFcommande.

... le commutateur / I, s'il est spécifié, indique de faire des comparaisons de chaînes insensibles à la casse.

cela peut être utile si vous souhaitez donner à vos utilisateurs une flexibilité insensible à la casse pour spécifier les paramètres.

IF /I "%1"=="-b" GOTO SPECIFIC
PENNSYLVANIE.
la source
5

Vous comparez des chaînes. Si un argument est omis, se %1développe en un blanc pour que les commandes deviennent IF =="-b" GOTO SPECIFICpar exemple (ce qui est une erreur de syntaxe). Mettez vos chaînes entre guillemets (ou crochets).

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
la source
SI [% 1] == [/?] Ne fonctionne pas mais si je fais SI [% 1] == [] ou "% 1" == "", alors cela fonctionne. Quoi qu'il en soit maintenant je peux y aller. Merci pour votre réponse rapide.
javauser71
5

En fait, toutes les autres réponses ont des défauts. Le moyen le plus fiable est:

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

Explication détaillée:

L'utilisation "%1"=="-b"plantera complètement si vous passez un argument avec des espaces et des guillemets. C'est la méthode la moins fiable.

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

C:\> run.bat "a b"

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

L'utilisation [%1]==[-b]est meilleure car elle ne plantera pas avec des espaces et des guillemets, mais elle ne correspondra pas si l'argument est entouré de guillemets.

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

C:\> run.bat "-b"

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

L'utilisation "%~1"=="-b"est la plus fiable. %~1supprimera les citations environnantes si elles existent. Cela fonctionne donc avec et sans guillemets, et aussi sans argument.

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
la source
1
Ce n'est pas la fin des crochets, vous voyez: IF [%~1]==[]- ça marche, et ça gère même "-b". Vous devez juste être capable de penser à l' intérieur de la boîte, euh, carré [crochets].
Tomasz Gandor
3

J'ai eu des difficultés récemment avec la mise en œuvre de commutateurs de paramètres complexes dans un fichier batch, voici donc le résultat de mes recherches. Aucune des réponses fournies n'est totalement sûre, exemples:

"%1"=="-?" ne correspondra pas si le paramètre est entre guillemets (nécessaire pour les noms de fichiers, etc.) ou se plantera si le paramètre est entre guillemets et contient des espaces (encore une fois souvent vu dans les noms de fichiers)

@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="-?"

Toute combinaison avec des crochets [%1]==[-?]ou [%~1]==[-?]échouera si le paramètre contient des espaces entre guillemets:

@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.

La solution la plus sûre proposée "%~1"=="-?"plantera avec un paramètre complexe qui comprend du texte en dehors des guillemets et du texte avec des espaces entre les guillemets:

@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.

La seule façon de garantir que tous les scénarios ci-dessus sont couverts est d'utiliser EnableDelayedExpansion et de transmettre les paramètres par référence (et non par valeur) à l'aide de variables. Alors même le scénario le plus complexe fonctionnera bien:

@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.Barev
la source
0

Le lot Windows a le mot clé DEFINED pour ce faire.

IF DEFINED %~1 foo
IF NOT DEFINED %~1 bar
Charles
la source
Merci David. Je ne sais pas pourquoi il n'y a pas eu de retour chariot et de nouvelle ligne entre IF et IF NOT. Je n'ai même pas remarqué.
Charles