Come controllare il parametro della riga di comando nel file ".bat"?


103

Il mio sistema operativo è Windows Vista. Ho bisogno di un file ".bat" in cui devo controllare se l'utente inserisce o meno un parametro della riga di comando. In caso affermativo, se il parametro è uguale a -b, farò qualcosa altrimenti contrassegnerò "Input non valido". Se l'utente non immette alcun parametro della riga di comando, farò qualcosa. Ho creato il seguente file .bat. Funziona per -be non è uguale ai -bcasi, ma non riesce quando l'utente non passa alcun parametro della riga di comando.

Ottengo sempre un errore:

GOTO was unexpected at this time.

Qualcuno può dirmi cosa sto facendo di sbagliato qui?


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!

Se aggiungi parentesi (come nella GOTO BLANKriga) alle altre due IFaffermazioni, questo risolve il problema?
Jeremiah Willcock

Risposte:


141

È necessario verificare che il parametro sia vuoto: if "%~1"=="" goto blank

Dopo averlo fatto, esegui un'opzione if / else su -b: if "%~1"=="-b" (goto specific) else goto unknown

Circondare i parametri tra virgolette semplifica il controllo di cose come parametri vuoti / vuoti / mancanti. "~" assicura che le virgolette doppie vengano rimosse se fossero nell'argomento della riga di comando.


Funziona !! Solo "altro" non è accettato. Ricevo l'errore: "else" non è riconosciuto come comando interno o esterno, programma eseguibile o file batch. Quindi ho aggiunto un altro IF per il caso "non uguale a -b". Grazie per la risposta rapida.
javauser71

7
L'ALTRO deve essere sulla stessa linea dell'IF, o deve essere direttamente dopo una parentesi
jeb

4
Questo non sembra funzionare per me se% 1 contiene spazi, il che potrebbe essere il caso se è il percorso completo di un eseguibile. Vedi la risposta di Jeremiah Willcock per una soluzione che funziona anche per i parametri con spazi nei loro valori.
Mark A. Fitzgerald

non sarà accettato se il tuo argomento è a File, in tal caso dovresti controllare solo existo not exist. Questo è il motivo per cui i tuoi argomenti dovrebbero essere ben definiti, o semplicemente usare powershell o vbScript (se sei negli anni '80 ..)

1
Questo fallisce per run.bat "a b". "%1"==""si blocca se l'argomento ha uno spazio. Vedere stackoverflow.com/a/46942471
wisbucky

27

Guarda http://ss64.com/nt/if.html per una risposta; il comando è IF [%1]==[] GOTO NO_ARGUMENTo simile.


1
Non solo funziona ANCHE! Funziona e basta, al contrario di "%1"=="". Devo approfondirlo nella mia risposta.
Tomasz Gandor

1
questo si interromperà quando viene citato% 1, ad es foo.bat "1st parameter" 2nd_param. Vedere stackoverflow.com/questions/2541767/...
Wilkie opaco

L'uso [%1]==[-b]non corrisponderà se arg è quotato. Esempio run.bat "-b". Vedere stackoverflow.com/a/46942471
wisbucky

20

La risposta breve: usa le parentesi quadre:

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

o (quando è necessario gestire gli argomenti tra virgolette, vedere la modifica di seguito):

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

Perché? potresti chiedere. Bene, proprio come ha menzionato Jeremiah Willcock: http://ss64.com/nt/if.html - lo usano! OK, ma cosa c'è di sbagliato nelle virgolette?

Di nuovo, risposta breve: sono "magici" - a volte le virgolette doppie (doppie) vengono convertite in virgolette singole (doppie). E devono combaciare, tanto per cominciare.

Considera questo piccolo script:

@rem argq.bat
@echo off

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

:done
echo Done.

Proviamolo:

C:\> argq bla bla
bla
bla
Done.

Sembra funzionare. Ma ora, passiamo alla seconda marcia:

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

Boom Questo non è stato valutato come vero, né come falso. La sceneggiatura è MORTA. Se avessi dovuto spegnere il reattore da qualche parte lungo la linea, beh, sfortuna. Ora morirai come Harry Daghlian.

Potresti pensare: OK, gli argomenti non possono contenere virgolette. Se lo fanno, succede. Sbagliato Ecco qualche consolazione:

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

O si. Non ti preoccupare - a volte questo sarà lavorare.

Proviamo un altro script:

@rem args.bat
@echo off

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

:done
echo Done.

Puoi metterti alla prova, che funziona bene per i casi sopra. Questo è logico: le virgolette non hanno nulla a che fare con le parentesi, quindi non c'è magia qui. Ma che dire di ravvivare gli argomenti con le parentesi?

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

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

Nessuna fortuna lì. Le parentesi non possono semplicemente soffocare cmd.exeil parser di.

Torniamo per un momento alle citazioni malvagie. Il problema era lì, quando l'argomento si è concluso con una citazione:

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

E se passo solo:

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

Lo script non verrà eseguito affatto. Lo stesso per args.bat:

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

Ma cosa ottengo, quando il numero di "caratteri "corrisponde" (cioè - è pari), in questo caso:

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

NIZZA - Spero che tu abbia imparato qualcosa su come i .batfile dividono i loro argomenti della riga di comando (SUGGERIMENTO: * Non è esattamente come in bash). L'argomento precedente contiene uno spazio. Ma le virgolette non vengono rimosse automaticamente.

E argq? Come reagisce a questo? Prevedibilmente:

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

Quindi, pensa prima di dire: "Sai cosa? Usa solo le virgolette. [Perché, a me, questo sembra più carino]".

modificare

Recentemente, ci sono stati commenti su questa risposta - beh, le parentesi quadrate "non possono gestire" il passaggio di argomenti tra virgolette e trattarli come se non fossero citati.

La sintassi:

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

Non è una virtù ritrovata di recente delle virgolette doppie, ma la visualizzazione di una chiara caratteristica di rimuovere le virgolette dalla variabile argomento, se il primo e l'ultimo carattere sono virgolette doppie.

Questa "tecnologia" funziona altrettanto bene con le parentesi quadre:

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

È stato utile sottolinearlo, quindi ho anche votato a favore della nuova risposta.

Infine, fan delle virgolette doppie, esiste un argomento del modulo ""nel tuo libro o è vuoto? Sto solo chiedendo;)


1
Le parentesi quadre [%1]==[-b]non corrisponderanno se arg è quotato come run.bat "-b". Vedere stackoverflow.com/a/46942471
wisbucky

Nota storica: [%1]==[-b]ed "%1"=="-b"erano gli stessi per win 98 e precedenti script batch di sistemi MS / PC-DOS. Poiché Win 2000 / NT ha introdotto la sintassi in if "%~1"=="-b"cui le virgolette hanno un significato speciale, questo è il modo in cui dovresti codificare gli script in quanto fornisce una protezione più robusta. Le virgolette doppie sfuggono al significato dei caratteri speciali (prova & | e% chars nella riga di comando). Il 99,9% degli esempi utilizza la sintassi delle virgolette doppie: il tuo esempio argq bla2" "bla3è solo maiuscolo per giustificare le parentesi quadre. Le virgolette doppie incorporate sono una ricetta per il disastro - basta dire
Salta R

@ SkipR - ecco perché nei filesystem di Windows non puoi avere questi caratteri speciali nei nomi. Non ho una dimostrazione matematica, ma penso che semplicemente NON tutto possa essere citato (nel senso di - reso letterale tramite una sequenza di escape, ecc.) Nella cmdshell. In altri sistemi a volte puoi citare tutto, incluso il carattere NUL. ( stackoverflow.com/questions/2730732/… ) - questa domanda mostra solo che è necessario utilizzare un programma esterno.
Tomasz Gandor

8

Oltre alle altre risposte, che sottoscrivo, potresti considerare di utilizzare lo /Iswitch del IFcomando.

... l'opzione / I, se specificata, dice di fare confronti tra stringhe senza distinzione tra maiuscole e minuscole.

può essere di aiuto se si desidera dare agli utenti flessibilità senza distinzione tra maiuscole e minuscole per specificare i parametri.

IF /I "%1"=="-b" GOTO SPECIFIC

5

Stai confrontando stringhe. Se un argomento viene omesso, si %1espande in uno spazio vuoto in modo che i comandi diventino IF =="-b" GOTO SPECIFICad esempio (che è un errore di sintassi). Racchiudi le tue stringhe tra virgolette (o parentesi quadre).

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

SE [% 1] == [/?] Non funziona ma se lo faccio SE [% 1] == [] o "% 1" == "", allora funziona. Comunque ora posso andare. Grazie per la sua pronta risposta.
javauser71

5

In realtà, tutte le altre risposte hanno dei difetti. Il modo più affidabile è:

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

Spiegazione dettagliata:

L'utilizzo si "%1"=="-b"bloccherà se si passa un argomento con spazi e virgolette. Questo è il metodo meno affidabile.

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

C:\> run.bat "a b"

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

L'uso [%1]==[-b]è migliore perché non si bloccherà con spazi e virgolette, ma non corrisponderà se l'argomento è racchiuso tra virgolette.

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

C:\> run.bat "-b"

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

L'utilizzo "%~1"=="-b"è il più affidabile. %~1rimuoverà le virgolette circostanti se esistono. Quindi funziona con e senza virgolette e anche senza argomenti.

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)

1
Questa non è la fine delle parentesi quadre, vedi: IF [%~1]==[]- Funziona e gestisce anche "-b". Devi solo essere in grado di pensare dentro la scatola, ehm, quadrato [parentesi].
Tomasz Gandor

3

Recentemente ho lottato con l'implementazione di interruttori di parametri complessi in un file batch, quindi ecco il risultato della mia ricerca. Nessuna delle risposte fornite è completamente sicura, esempi:

"%1"=="-?" non corrisponderà se il parametro è racchiuso tra virgolette (necessario per i nomi dei file ecc.) o si bloccherà se il parametro è tra virgolette e ha spazi (di nuovo spesso visto nei nomi dei file)

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

Qualsiasi combinazione con parentesi quadre [%1]==[-?]o [%~1]==[-?]fallirà nel caso in cui il parametro abbia spazi tra virgolette:

@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 soluzione più sicura proposta "%~1"=="-?"andrà in crash con un parametro complesso che include testo fuori dalle virgolette e testo con spazi all'interno delle virgolette:

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

L'unico modo per garantire che tutti gli scenari precedenti siano coperti è usare EnableDelayedExpansion e passare i parametri per riferimento (non per valore) utilizzando le variabili. Quindi anche lo scenario più complesso funzionerà bene:

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

0

Il batch di Windows ha la parola chiave DEFINED per eseguire questa operazione.

IF DEFINED %~1 foo
IF NOT DEFINED %~1 bar

Grazie David. Non so perché non ci sia stato un ritorno a capo e una nuova linea tra IF e IF NOT. Non me ne sono nemmeno accorto.
Charles,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.