Qual è il modo corretto di verificare se un parametro è vuoto in un file batch?


214

Devo verificare se è impostata o meno una variabile. Ho provato diverse tecniche ma sembrano fallire ogni volta che %1è racchiuso tra virgolette come nel caso in cui lo %1è "c:\some path with spaces".

IF NOT %1 GOTO MyLabel // This is invalid syntax
IF "%1" == "" GOTO MyLabel // Works unless %1 has double quotes which fatally kills bat execution
IF %1 == GOTO MyLabel // Gives an unexpected GOTO error.

Secondo questo sito , questi sono i IFtipi di sintassi supportati . Quindi, non vedo un modo per farlo.

IF [NOT] ERRORLEVEL number command
IF [NOT] string1==string2 command
IF [NOT] EXIST filename command

1
Sui miei sistemi (Windows 2003 e Windows 7), if "%1" == "" GOTO MyLabelnon uccide fatalmente l'esecuzione dello script fintanto che %1ha un numero pari di virgolette. Vedo che un numero dispari di virgolette doppie %1uccide l'esecuzione dello script con questo errore: The syntax of the command is incorrect.la soluzione che segue che usa parentesi quadre per risolvere il problema è stata contrassegnata come la risposta corretta ma non sembra andare meglio . Quella soluzione fallisce anche con lo stesso errore quando %1ha un numero dispari di virgolette doppie.
Susam Pal

@SusamPal Interessante. Prova la versione tra parentesi sotto di essa e vedi se funziona. Quello che ho testato di più. Ho appena aggiornato la risposta accettata un paio di giorni fa.
Blak3r

La risposta di Dan Story sembra funzionare davvero bene. Ho usato la versione usando parentesi quadre.
Susam Pal,

un buon esempio "catch all": stackoverflow.com/questions/830565/… che copre sia l'argomento file / directory sia il mix generico stringa / numero nell'argomento.

Così frustrante: IF DEFINEDlavorare solo su variabili di ambiente anziché su variabili di script è un tale spreco di potenziale!
kayleeFrye_onDeck

Risposte:


292

Utilizzare le parentesi quadre anziché le virgolette:

IF [%1] == [] GOTO MyLabel

Le parentesi non sono sicure : utilizzare solo parentesi quadre.


11
le parentesi non sono sicure! Contenuto come &in %1interromperà la linea
jeb

14
L'uso di altri caratteri come if #%1#==##o if [%1]==[]è valido purché non vi siano spazi nell'argomento, altrimenti si otterrà un …was unexpected at this timeerrore.
Synetech,

12
E usare "%~1"è davvero un approccio migliore, come ho già detto nella mia risposta.
jamesdlin,

8
Ragazzi, @jamesdlin è corretto. Questo approccio non funzionerà se il testo della variabile ha spazi o lo è ==. Usa invece la sua risposta.
James Ko,

4
Non lo chiarisci it DOES NOT work with spaces. Usa invece la risposta @jamesdlin.
JB. Con Monica.

153

Puoi usare:

IF "%~1" == "" GOTO MyLabel

per eliminare l'insieme esterno di virgolette. In generale, questo è un metodo più affidabile rispetto all'utilizzo di parentesi quadre perché funzionerà anche se la variabile contiene spazi.


9
Questo è davvero un buon modo per farlo. Usando ~, si rimuovono le virgolette esterne se sono presenti, ma poi si aggiungono nuovamente manualmente (garantendo solo un set). Inoltre, è necessario utilizzare le virgolette se l'argomento contiene spazi (ho imparato questo il senso duro quando la mia versione precedente di usare #o di staffe invece di citazioni causato argomenti con spazi per gettare un …was unexpected at this timeerrore.)
Synetech

4
questo vale anche per variabili generali come% MYVAR% anziché argomenti come% 1?
simpleuser

4
@simpleuser Spiacenti, hai ragione, non funziona con le variabili di ambiente generali.
jamesdlin,

1
fai attenzione alle stringhe che usano il doppio "" 'come sequenza di escape - lo script si arresterà in modo anomalo quando tenterà il confronto. Ad esempio, il ""this string will crash the comparison""doppio ""' è la sequenza di escape corretta e fare una sostituzione sul doppio '"' non riuscirà se il la stringa è vuota
Tydaeus,

1
@Amalgovinus Probabilmente potresti passare la variabile come argomento a un sottoprogramma e lasciarlo usare "%~1".
jamesdlin,

38

Una delle migliori soluzioni semi è copiare %1in una variabile e quindi utilizzare l'espansione ritardata, come delayedExp. è sempre sicuro contro qualsiasi contenuto.

set "param1=%~1"
setlocal EnableDelayedExpansion
if "!param1!"=="" ( echo it is empty )
rem ... or use the DEFINED keyword now
if defined param1 echo There is something

Il vantaggio di questo è che gestire param1 è assolutamente sicuro.

E l'impostazione di param1 funzionerà in molti casi, come

test.bat hello"this is"a"test
test.bat you^&me

Ma fallisce ancora con strani contenuti come

test.bat ^&"&

Essere in grado di ottenere una risposta corretta al 100% per l'esistenza

Rileva se %1è vuoto, ma per alcuni contenuti non può recuperarli.
Questo può anche essere utile per distinguere tra un vuoto %1e uno con "".
Usa la capacità del CALLcomando di fallire senza interrompere il file batch.

@echo off
setlocal EnableDelayedExpansion
set "arg1="
call set "arg1=%%1"

if defined arg1 goto :arg_exists

set "arg1=#"
call set "arg1=%%1"
if "!arg1!" EQU "#" (
    echo arg1 exists, but can't assigned to a variable
    REM Try to fetch it a second time without quotes
    (call set arg1=%%1)
    goto :arg_exists
)

echo arg1 is missing
exit /b

:arg_exists
echo arg1 exists, perhaps the content is '!arg1!'

Se vuoi essere al 100% a prova di proiettile per recuperare il contenuto, potresti leggere Come ricevere anche i parametri della riga di comando più strani?


18

Da IF / ?:

Se le estensioni di comando sono abilitate, SE cambia come segue:

IF [/I] string1 compare-op string2 command
IF CMDEXTVERSION number command
IF DEFINED variable command

......

Il condizionale DEFINED funziona esattamente come EXISTS tranne per il fatto che prende un nome di variabile di ambiente e restituisce true se la variabile di ambiente è definita.


1
Sì, in realtà ho provato questo approccio e da quello che potrei dire funziona solo con le variabili AMBIENTE. Pertanto, non ha funzionato con% 1 o una variabile definita all'interno del file batch.
Blak3r

2
Questo è vero solo per %1e simili. Le "variabili definite all'interno del file batch" sono in realtà variabili di ambiente mentre il file batch è in esecuzione e su cui è possibile utilizzarle IF DEFINED.
zb226

8

Purtroppo non ho abbastanza reputazione per commentare o votare le risposte attuali a cui ho dovuto scrivere la mia.

Inizialmente la domanda del PO diceva "variabile" anziché "parametro", il che diventava molto confuso, soprattutto perché questo era il collegamento numero uno in Google per cercare come verificare le variabili vuote. Dalla mia risposta originale, Stephan ha modificato la domanda originale per utilizzare la terminologia corretta, ma invece di eliminare la mia risposta ho deciso di lasciarla per aiutare a chiarire qualsiasi confusione, soprattutto nel caso in cui Google stia ancora inviando persone qui per le variabili:

% 1 NON È UN VARIABILE! È UN PARAMETRO DELLA LINEA DI COMANDO.

Distinzione molto importante. Un singolo segno di percentuale con un numero dopo che fa riferimento a un parametro della riga di comando e non a una variabile.

Le variabili vengono impostate utilizzando il comando set e vengono richiamate utilizzando i segni del 2 percento, uno prima e uno dopo. Ad esempio% myvar%

Per verificare una variabile vuota, utilizzare la sintassi "se non definita" (i comandi esplicitamente per le variabili non richiedono alcun segno di percentuale), ad esempio:

set myvar1=foo  
if not defined myvar1 echo You won't see this because %myvar1% is defined.  
if not defined myvar2 echo You will see this because %myvar2% isn't defined.

(Se vuoi testare i parametri della riga di comando, ti consiglio di fare riferimento alla risposta di jamesdlin.)


1
hai ragione. Ma il modo corretto sarebbe stato semplicemente correggere il titolo da if variable is emptya if parameter is empty. L'ho appena fatto. (con il rischio di invalidare alcune delle risposte, che hanno verificato le variabili anziché i parametri e quindi non sono valide in quanto non hanno risposto alla domanda)
Stephan,

1
OK grazie Stephan, non avevo capito che potevi farlo. Ho modificato la mia risposta per riflettere l'aggiornamento.
AutoMattTick

6

Utilizzare "IF DEFINED command command" per testare la variabile nel file batch.

Ma se vuoi testare i parametri batch, prova sotto i codici per evitare input difficili (come "1 2" o ab ^> cd)

set tmp="%1"
if "%tmp:"=.%"==".." (
    echo empty
) else (
    echo not empty
)

5

Ho provato con il codice qui sotto ed è tutto a posto.

@echo off

set varEmpty=
if not "%varEmpty%"=="" (
    echo varEmpty is not empty
) else (
    echo varEmpty is empty
)
set varNotEmpty=hasValue
if not "%varNotEmpty%"=="" (
    echo varNotEmpty is not empty
) else (
    echo varNotEmpty is empty
)

La tua soluzione fallisce quando la variabile contiene un preventivo. A proposito esiste la sintassi IF DEFINED varper un motivo
jeb

4

Di solito lo uso:

IF "%1."=="." GOTO MyLabel

Se% 1 è vuoto, l'IF confronterà "." per "." che valuterà come vero.


4
Questo non è corretto È la stessa cosa di: SE "% 1" == "" il motivo di questo post è stato se% 1 stesso ha delle virgolette che falliscono.
Blak3r

Stai provando a verificare se% 1 è vuoto o se contiene virgolette? La domanda non è chiara. La mia risposta funziona se non viene specificato nulla sulla riga di comando per% 1.
aphoria,

> Stai provando a testare se% 1 è vuoto o ha virgolette? @aphoria, deve essere in grado di gestire entrambi.
Synetech,

Ho usato questo per capire se% 1% era stato impostato, funzionava bene per me. Grazie, buona risposta!
Charlie A

4

Ho creato questo piccolo script batch basato sulle risposte qui, poiché ce ne sono molte valide. Sentiti libero di aggiungere a questo finché segui lo stesso formato:

REM Parameter-testing

Setlocal EnableDelayedExpansion EnableExtensions

IF NOT "%~1"=="" (echo Percent Tilde 1 failed with quotes) ELSE (echo SUCCESS)
IF NOT [%~1]==[] (echo Percent Tilde 1 failed with brackets) ELSE (echo SUCCESS)
IF NOT  "%1"=="" (echo Quotes one failed) ELSE (echo SUCCESS)
IF NOT [%1]==[] (echo Brackets one failed) ELSE (echo SUCCESS)
IF NOT "%1."=="." (echo Appended dot quotes one failed) ELSE (echo SUCCESS)
IF NOT [%1.]==[.] (echo Appended dot brackets one failed) ELSE (echo SUCCESS)

pause

4

La stringa vuota è una coppia di double-quotes/ "", possiamo solo testare la lunghezza:

set ARG=%1
if not defined ARG goto nomore

set CHAR=%ARG:~2,1%
if defined CHAR goto goon

quindi prova 2 caratteri contro double-quotes:

if ^%ARG:~1,1% == ^" if ^%ARG:~0,1% == ^" goto blank
::else
goto goon

Ecco uno script batch con cui puoi giocare. Penso che catturi correttamente la stringa vuota.

Questo è solo un esempio, devi solo personalizzare 2 (o 3?) Passaggi in base al tuo script.

@echo off
if not "%OS%"=="Windows_NT" goto EOF
:: I guess we need enableExtensions, CMIIW
setLocal enableExtensions
set i=0
set script=%0

:LOOP
set /a i=%i%+1

set A1=%1
if not defined A1 goto nomore

:: Assumption:
:: Empty string is (exactly) a pair of double-quotes ("")

:: Step out if str length is more than 2
set C3=%A1:~2,1%
if defined C3 goto goon

:: Check the first and second char for double-quotes
:: Any characters will do fine since we test it *literally*
if ^%A1:~1,1% == ^" if ^%A1:~0,1% == ^" goto blank
goto goon

:goon
echo.args[%i%]: [%1]
shift
goto LOOP

:blank
echo.args[%i%]: [%1] is empty string
shift
goto LOOP

:nomore
echo.
echo.command line:
echo.%script% %*

:EOF

Questo risultato del test di tortura:

.test.bat :: ""  ">"""bl" " "< "">"  (")(") "" :: ""-"  " "( )"">\>" ""
args[1]: [::]
args[2]: [""] is empty string
args[3]: [">"""bl" "]
args[4]: ["< "">"]
args[5]: [(")(")]
args[6]: [""] is empty string
args[7]: [::]
args[8]: [""-"  "]
args[9]: ["( )"">\>"]
args[10]: [""] is empty string

command line:
.test.bat :: ""  ">"""bl" " "< "">"  (")(") "" :: ""-"  " "( )"">\>" ""

È sbagliato, una stringa vuota non è una stringa con due virgolette doppie, ""una stringa vuota è una stringa vuota `` e in batch una variabile vuota è una variabile indefinita. Puoi definire che per i tuoi argomenti le virgolette esterne verranno rimosse, ma poi la stringa è ancora vuota con una lunghezza di 0
jeb

In questo contesto (vinci argomenti cmd), non puoi denotare una stringa vuota in nessun altro modo, nemmeno con la doppia virgoletta singola che ugualmente svuota sotto la shell unix.
user6801759,

Sì, ""vengono utilizzati anche per stringhe vuote, ma è abbastanza facile da usare %~1per rimuovere le virgolette esterne. non è necessario utilizzare una soluzione così complessa
jeb

Hai ragione, potrei dire impropriamente, non solo per stringa vuota ma un modo sicuro per enumerare gli argomenti. Altri modi come "%~1"==""falliranno con argomenti come il "Long File Name".txtquale è un argomento valido. modifica : E sicuramente non è complesso come hai detto. Solo 2 passaggi sopra per il test, il resto è un esempio dettagliato.
user6801759

"se non definito ARG" sembra funzionare perfettamente (la mia variabile non proviene dalla riga di comando)
GrayFace


3

Script 1:

Input ("Rimuovi Quotes.cmd" "Questo è un test")

@ECHO OFF

REM Set "string" variable to "first" command line parameter
SET STRING=%1

REM Remove Quotes [Only Remove Quotes if NOT Null]
IF DEFINED STRING SET STRING=%STRING:"=%

REM IF %1 [or String] is NULL GOTO MyLabel
IF NOT DEFINED STRING GOTO MyLabel


REM   OR   IF "." equals "." GOTO MyLabel
IF "%STRING%." == "." GOTO MyLabel

REM GOTO End of File
GOTO :EOF

:MyLabel
ECHO Welcome!

PAUSE

Output (nessuno,% 1 NON era vuoto, vuoto o NULL):


Esegui ("Rimuovi Quotes.cmd") senza parametri con lo script sopra 1

Output (% 1 è vuoto, vuoto o NULL):

Welcome!

Press any key to continue . . .

Nota: se si imposta una variabile all'interno di IF ( ) ELSE ( )un'istruzione, questa non sarà disponibile su DEFINED fino a quando non esce dall'istruzione "IF" (a meno che non sia abilitata "Espansione ritardata variabile"; una volta abilitata utilizzare un punto esclamativo "!" Al posto del simbolo "%" percentuale}.

Per esempio:

Script 2:

Input ("Rimuovi Quotes.cmd" "Questo è un test")

@ECHO OFF

SETLOCAL EnableDelayedExpansion

SET STRING=%0
IF 1==1 (
  SET STRING=%1
  ECHO String in IF Statement='%STRING%'
  ECHO String in IF Statement [delayed expansion]='!STRING!'
) 

ECHO String out of IF Statement='%STRING%'

REM Remove Quotes [Only Remove Quotes if NOT Null]
IF DEFINED STRING SET STRING=%STRING:"=%

ECHO String without Quotes=%STRING% 

REM IF %1 is NULL GOTO MyLabel
IF NOT DEFINED STRING GOTO MyLabel

REM GOTO End of File
GOTO :EOF

:MyLabel
ECHO Welcome!

ENDLOCAL
PAUSE

Produzione:

C:\Users\Test>"C:\Users\Test\Documents\Batch Files\Remove Quotes.cmd" "This is a Test"  
String in IF Statement='"C:\Users\Test\Documents\Batch Files\Remove Quotes.cmd"'  
String in IF Statement [delayed expansion]='"This is a Test"'  
String out of IF Statement='"This is a Test"'  
String without Quotes=This is a Test  

C:\Users\Test>  

Nota: rimuoverà anche le virgolette dall'interno della stringa.

Ad esempio (utilizzando lo script 1 o 2): C: \ Users \ Test \ Documents \ Batch Files> "Rimuovi Quotes.cmd" "Questo è" un "Test"

Output (Script 2):

String in IF Statement='"C:\Users\Test\Documents\Batch Files\Remove Quotes.cmd"'  
String in IF Statement [delayed expansion]='"This is "a" Test"'  
String out of IF Statement='"This is "a" Test"'  
String without Quotes=This is a Test  

Eseguire ("Rimuovi Quotes.cmd") senza parametri nello Script 2:

Produzione:

Welcome!

Press any key to continue . . .

3

Per riassumere:

set str=%~1
if not defined str ( echo Empty string )

Questo codice genererà "Stringa vuota" se% 1 è "" o "o vuoto. Aggiunto alla risposta accettata che al momento non è corretta.


0

Ho avuto molti problemi con molte risposte in rete. La maggior parte funziona per la maggior parte delle cose, ma c'è sempre un caso d'angolo che rompe ciascuno.
Forse non funziona se ha virgolette, forse si rompe se non ha virgolette, errore di sintassi se var ha uno spazio, alcuni funzioneranno solo su parametri (al contrario di variabili d'ambiente), altre tecniche consentono un vuoto serie di virgolette da passare come 'definite', e alcune più complicate non ti permetteranno di fare una catena elsedopo

Ecco una soluzione di cui sono felice, per favore fatemi sapere se trovate un caso d'angolo per cui non funzionerà.

:ifSet
if "%~1"=="" (Exit /B 1) else (Exit /B 0)

Avere quella subroutine in uno script, o nel suo .bat, dovrebbe funzionare.
Quindi se vuoi scrivere (in pseudo):

if (var)
then something
else somethingElse

Tu puoi scrivere:

(Call :ifSet %var% && (
    Echo something
)) || (
    Echo something else
)

Ha funzionato per tutti i miei test:

(Call :ifSet && ECHO y) || ECHO n
(Call :ifSet a && ECHO y) || ECHO n
(Call :ifSet "" && ECHO y) || ECHO n
(Call :ifSet "a" && ECHO y) || ECHO n
(Call :ifSet "a a" && ECHO y) || ECHO n

Echo'd n, y, n, y,y


Altri esempi:

  • Vuoi solo controllare if?Call :ifSet %var% && Echo set
  • Solo se non (solo l'altro)? Call :ifSet %var% || Echo set
  • Verifica di un argomento passato; funziona bene.Call :ifSet %1 && Echo set
  • Non volevi ostruire i tuoi script / codice duplicato, quindi lo hai inserito nel suo ifSet.bat? Nessun problema:((Call ifSet.bat %var%) && Echo set) || (Echo not set)

Trovato un caso; Se provi la sintassi if with else e l'ultimo comando nel blocco then fallisce, l'altro eseguirà (Call ifSet.bat YES && (Echo true & Echo x | findstr y)) || Echotrue false
:,

In realtà, se questo è un problema e puoi occuparti di una linea aggiuntiva, puoi mitigarlo chiamando ifSetda solo, quindi usandoIf %errorlevel% EQU 0 (x) Else (y)
Hashbrown

In quali casi la risposta accettata (usa parentesi quadre) non funziona? E puoi spiegare cosa fa l'uscita / B
blak3r

per qualche motivo quando l'ho provato si è rotto quando ho usato le setvariabili (come [%bob%], lavorando solo per argomenti come [%2]) ma ora ricontrollando funziona. Immagino che la mia unica lamentela []ora sia che lascia passare le virgolette vuote, mentre questo non lo
farà

Il /Bflag interrompe la chiusura dell'intero batch, uscendo solo dalla subroutine o dal callbatch. A meno che tu non stia chiedendo cosa sta facendo l' intero comando ; restituisce un codice di errore per comunicare allo script chiamante il risultato della subroutine ( 0pass, 1fail), utilizzabile tramite la logica booleana nella risposta o tramite %errorlevel%i commenti sopra
Hashbrown,

0

Usando! anziché "per controllo stringa vuoto

@echo off
SET a=
SET b=Hello
IF !%a%! == !! echo String a is empty
IF !%b%! == !! echo String b is empty

1
Il consiglio è davvero pessimo. Le virgolette possono gestire almeno spazi e caratteri speciali, ma i punti esclamativi no. E i punti esclamativi diventano davvero cattivi qui quando è abilitata l'espansione ritardata
jeb

0

Sono entrato da poco meno di un mese (anche se mi è stato chiesto 8 anni fa) ... Spero che ormai sia andato oltre i file batch. ;-) Lo facevo sempre. Non sono sicuro di quale sia l'obiettivo finale, però. Se è pigro come me, il mio go.bat funziona per cose del genere. (Vedi sotto) Ma, 1, il comando nell'OP potrebbe non essere valido se si utilizza direttamente l'input come comando. vale a dire,

"C:/Users/Me"

è un comando non valido (o utilizzato in precedenza su un'unità diversa). Devi romperlo in due parti.

C:
cd /Users/Me

E, 2, cosa significa "definito" o "non definito"? GIGO. Uso il valore predefinito per rilevare errori. Se l'input non viene catturato, scende per aiutare (o un comando predefinito). Quindi, nessun input non è un errore. Puoi provare a inserire un cd all'ingresso e catturare l'errore se ce n'è uno. (Ok, usando go "download (solo una parentesi) viene catturato da DOS. (Duro!))

cd "%1"
if %errorlevel% neq 0 goto :error

E, 3, le virgolette sono necessarie solo attorno al percorso, non al comando. vale a dire,

"cd C:\Users" 

era cattivo (o usato ai vecchi tempi) a meno che tu non fossi su un altro disco.

cd "\Users" 

è funzionale.

cd "\Users\Dr Whos infinite storage space"

funziona se hai spazi nel tuo percorso.

@REM go.bat
@REM The @ sigh prevents echo on the current command
@REM The echo on/off turns on/off the echo command. Turn on for debugging
@REM You can't see this.
@echo off
if "help" == "%1" goto :help

if "c" == "%1" C:
if "c" == "%1" goto :done

if "d" == "%1" D:
if "d" == "%1" goto :done

if "home"=="%1" %homedrive%
if "home"=="%1" cd %homepath%
if "home"=="%1" if %errorlevel% neq 0 goto :error
if "home"=="%1" goto :done

if "docs" == "%1" goto :docs

@REM goto :help
echo Default command
cd %1
if %errorlevel% neq 0 goto :error
goto :done

:help
echo "Type go and a code for a location/directory
echo For example
echo go D
echo will change disks (D:)
echo go home
echo will change directories to the users home directory (%homepath%)
echo go pictures
echo will change directories to %homepath%\pictures
echo Notes
echo @ sigh prevents echo on the current command
echo The echo on/off turns on/off the echo command. Turn on for debugging
echo Paths (only) with folder names with spaces need to be inclosed in         quotes (not the ommand)
goto :done

:docs
echo executing "%homedrive%%homepath%\Documents"
%homedrive%
cd "%homepath%\Documents"\test error\
if %errorlevel% neq 0 goto :error
goto :done

:error
echo Error: Input (%1 %2 %3 %4 %5 %6 %7 %8 %9) or command is invalid
echo go help for help
goto :done

:done

c'è una ragione per cd' /dswitch: cd /d "C:\Users\Me" (and the proper path delimeter for Windows is `, no /).
Stephan,
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.