¿Cuál es la forma correcta de probar si un parámetro está vacío en un archivo por lotes?

Necesito probar si una variable está configurada o no. He intentado varias técnicas, pero parecen fallar cuando %1 está rodeado por comillas, como el caso en que %1 es "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. 

Según este sitio , estos son los tipos de syntax IF soportados. Entonces, no veo una manera de hacerlo.

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

Utilice corchetes en lugar de comillas:

 IF [%1] == [] GOTO MyLabel 

Los paréntesis son inseguros : solo use corchetes.

Puedes usar:

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

para quitar el conjunto externo de comillas. En general, este es un método más confiable que usar corchetes porque funcionará incluso si la variable tiene espacios.

Una de las mejores semi soluciones es copiar %1 en una variable y luego utilizar la expansión retardada, como delayyedExp. siempre es seguro contra cualquier contenido.

 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 

La ventaja de esto es que lidiar con param1 es absolutamente seguro.

Y el ajuste de param1 funcionará en muchos casos, como

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

Pero fallará con contenidos extraños como

 test.bat "&"^& 

Si desea que sea al 99% a prueba de balas, ¿podría leer Cómo recibir incluso los parámetros de línea de comando más extraños?

De IF / ?:

Si las extensiones de comando están habilitadas, SI cambia de la siguiente manera:

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

……

El condicional DEFINED funciona igual que EXISTS, excepto que toma un nombre de variable de entorno y devuelve true si se define la variable de entorno.

Utilice “comando de variable IF DEFINED” para probar la variable en el archivo por lotes.

Pero si desea probar los parámetros del lote, intente los siguientes códigos para evitar entradas complicadas (como “1 2” o ab ^> cd)

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

La cadena vacía es un par de double-quotes / "" , solo podemos probar la longitud:

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

luego prueba 2 caracteres contra double-quotes :

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

Aquí hay un script por lotes con el que puedes jugar. Creo que atrapa correctamente la cadena vacía.

Esto es solo un ejemplo, solo necesita personalizar 2 (o 3?) Pasos anteriores de acuerdo a su secuencia de comandos.

 @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 /ai=%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 

Este resultado de la prueba de 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" " "< "">" (")(") "" :: ""-" " "( )"">\>" "" 

Lamentablemente, no tengo la reputación suficiente para comentar o votar sobre las respuestas actuales a las que he tenido que escribir las mías.

Originalmente, la pregunta del OP decía “variable” en lugar de “parámetro”, lo que se volvió muy confuso, especialmente porque este era el enlace número uno en google para buscar cómo probar las variables en blanco. Desde mi respuesta original, Stephan ha editado la pregunta original para usar la terminología correcta, pero en lugar de eliminar mi respuesta, decidí dejarla para ayudar a aclarar cualquier confusión, especialmente en caso de que Google todavía esté enviando gente aquí por variables también:

% 1 NO ES UN VARABLE! ES UN PARÁMETRO DE LA LÍNEA DE COMANDOS.

Distinción muy importante. Un solo signo de porcentaje con un número después de él se refiere a un parámetro de línea de comando, no a una variable.

Las variables se establecen usando el comando set y se recuperan usando signos de 2 por ciento, uno antes y otro después. Por ejemplo% myvar%

Para probar una variable vacía, utiliza la syntax “if not defined” (los comandos explícitamente para las variables no requieren ningún signo de porcentaje), por ejemplo:

 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. 

(Si desea probar los parámetros de la línea de comando, le recomiendo referirse a la respuesta de jamesdlin).

Usualmente uso esto:

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

Si% 1 está vacío, el IF comparará “.” a “.” que evaluará a verdadero.

Script 1:

Entrada (“Quitar Quotes.cmd” “Esto es una prueba”)

 @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 

Salida (No hay ninguno,% 1 NO estaba en blanco, vacío o NULO):


Ejecutar (“Quitar Quotes.cmd”) sin ningún parámetro con la secuencia de comandos anterior 1

Salida (% 1 está en blanco, vacío o NULO):

 Welcome! Press any key to continue . . . 

Nota: Si establece una variable dentro de una instrucción IF ( ) ELSE ( ) , no estará disponible para DEFINED hasta que salga de la instrucción “IF” (a menos que esté habilitada “Expansión de variable retrasada”; una vez habilitada, use un signo de exclamación ” ! “en lugar del porcentaje”% “símbolo}.

Por ejemplo:

Script 2:

Entrada (“Quitar Quotes.cmd” “Esto es una prueba”)

 @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 

Salida:

 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: También eliminará las comillas de dentro de la cadena.

Por ejemplo (usando el script 1 o 2): C: \ Users \ Test \ Documents \ Batch Files> “Quotes Quotes.cmd” “Esto es” un “Test”

Salida (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 

Ejecutar (“Quitar Quotes.cmd”) sin ningún parámetro en la secuencia de comandos 2:

Salida:

 Welcome! Press any key to continue . . . 

Creé este pequeño script por lotes basado en las respuestas aquí, ya que hay muchos válidos. Siéntase libre de agregar a esto siempre y cuando siga el mismo 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 

Para resumir las cosas:

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

Este código arrojará “Cadena vacía” si% 1 es “” o “” o está vacío. Se agregó a la respuesta aceptada que actualmente es incorrecta.

Puedes usar

 if defined (variable) echo That's defined! if not defined (variable) echo Nope. Undefined. 

He tenido muchos problemas con muchas respuestas en la red. La mayoría trabaja para la mayoría de las cosas, pero siempre hay un caso de esquina que las rompe.
Tal vez no funcione si tiene citas, tal vez se rompa si no tiene comillas, error de syntax si la var tiene un espacio, algunas solo trabajarán en parámetros (a diferencia de las variables de entorno), otras técnicas permiten un vacío conjunto de citas para pasar como ‘definido’, y algunas más complicadas no le permitirán encadenar a else después.

Aquí hay una solución con la que estoy contento, por favor avíseme si encuentra un caso en la esquina que no funcionará.

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

Tener esa subrutina en tu script, o en su propio .bat , debería funcionar.
Entonces, si quisieras escribir (en pseudo):

 if (var) then something else somethingElse 

Puedes escribir:

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

Funcionó para todas mis pruebas:

 (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 "aa" && ECHO y) || ECHO n 

Echo’d n , y , n , y , y


Más ejemplos:

  • ¿Quieres comprobar if ? Call :ifSet %var% && Echo set
  • ¿Solo si no (solo el otro)? Call :ifSet %var% || Echo set
  • Comprobando un argumento pasado; funciona bien. Call :ifSet %1 && Echo set
  • ¿No quería obstruir sus scripts / código de engaño, por lo que lo puso en su propio ifSet.bat ? No hay problema: ((Call ifSet.bat %var%) && Echo set) || (Echo not set) ((Call ifSet.bat %var%) && Echo set) || (Echo not set)

Utilizando ! en lugar de “para comprobación de cadena vacía

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

Pruebo con el código a continuación y está bien.

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

Ingresé con menos de un mes de antigüedad (a pesar de que se me preguntó hace 8 años) … espero que ahora se haya movido más allá de los archivos por lotes. 😉 Solía ​​hacer esto todo el tiempo. Aunque no estoy seguro de cuál es el objective final. Si es perezoso como yo, mi go.bat trabaja para cosas como esas. (Consulte a continuación) Pero, 1, el comando en el OP podría no ser válido si está usando directamente la entrada como un comando. es decir,

 "C:/Users/Me" 

es un comando no válido (o solía serlo si estuviera en un disco diferente). Necesitas dividirlo en dos partes.

 C: cd /Users/Me 

Y, 2, ¿qué significa “definido” o “indefinido”? GIGO. Utilizo el valor predeterminado para detectar errores. Si la entrada no queda atrapada, se convierte en ayuda (o un comando predeterminado). Entonces, ninguna entrada no es un error. Puede intentar hacer un cd a la entrada y detectar el error si hay uno. (Ok, usando ir “descargas (solo una paren) es capturada por DOS. (Harsh!))

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

Y, 3, las comillas son necesarias solo alrededor de la ruta, no del comando. es decir,

 "cd C:\Users" 

era malo (o estaba acostumbrado en los viejos tiempos) a menos que estuvieras en una unidad diferente.

 cd "\Users" 

es funcional.

 cd "\Users\Dr Whos infinite storage space" 

funciona si tienes espacios en tu camino.

 @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