¿Cómo comprobar el parámetro de la línea de comandos en el archivo ".bat"?

103

Mi sistema operativo es Windows Vista. Necesito tener un archivo ".bat" donde necesito verificar si el usuario ingresa algún parámetro de línea de comando o no. Si es así, si el parámetro es igual a, -bentonces haré algo, de lo contrario, marcaré "Entrada no válida". Si el usuario no ingresa ningún parámetro de línea de comando, haré algo. He creado el siguiente archivo .bat. Funciona para casos -by no es igual a ellos -b, pero falla cuando el usuario no pasa ningún parámetro de línea de comandos.

Siempre obtengo un error:

GOTO was unexpected at this time.

¿Alguien puede decirme qué estoy haciendo mal aquí?


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
fuente
Si agrega corchetes (como en la GOTO BLANKlínea) a las otras dos IFdeclaraciones, ¿eso soluciona el problema?
Jeremiah Willcock

Respuestas:

141

Debe verificar que el parámetro esté en blanco: if "%~1"=="" goto blank

Una vez que hayas hecho eso, haz un interruptor if / else en -b: if "%~1"=="-b" (goto specific) else goto unknown

Rodear los parámetros con comillas facilita la verificación de cosas como parámetros en blanco / vacíos / faltantes. "~" asegura que las comillas dobles se eliminen si estaban en el argumento de la línea de comandos.

más afrazier
fuente
¡¡Esto funciona!! Solo no se acepta "else". Recibo el error: "else" no se reconoce como un comando interno o externo, programa operable o archivo por lotes. Así que agregué otro IF para el caso "no igual a -b". Gracias por la rápida respuesta.
javauser71
7
El ELSE tiene que estar en la misma línea que el IF, o tiene que estar directamente después de un paréntesis
jeb
4
Esto no parece funcionar para mí si% 1 contiene espacios, que puede ser el caso si es la ruta completa a un ejecutable. Vea la respuesta de Jeremiah Willcock para una solución que funciona incluso para parámetros con espacios en sus valores.
Mark A. Fitzgerald
no se aceptará si su argumento es un File, en ese caso, solo debe marcar existo not exist. Es por eso que sus argumentos deben estar bien definidos, o simplemente usar powershell o vbScript (si está en los años 80 ..)
1
Esto falla run.bat "a b". "%1"==""se bloquea si el argumento tiene un espacio. Ver stackoverflow.com/a/46942471
wisbucky
27

Mire http://ss64.com/nt/if.html para obtener una respuesta; el comando es IF [%1]==[] GOTO NO_ARGUMENTo similar.

Jeremías Willcock
fuente
1
¡No solo esto TAMBIÉN funciona! Simplemente funciona, a diferencia de "%1"=="". Tengo que desarrollar eso en mi propia respuesta.
Tomasz Gandor
1
esto se romperá cuando se cotice% 1, por ejemplo foo.bat "1st parameter" 2nd_param. Ver stackoverflow.com/questions/2541767/…
Matt Wilkie
El uso [%1]==[-b]no coincidirá si se cita arg. Ejemplo run.bat "-b". Ver stackoverflow.com/a/46942471
wisbucky
20

La respuesta corta: use corchetes:

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

o (cuando necesite manejar argumentos entre comillas, consulte la Edición a continuación):

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

¿Por qué? podría preguntar. Bueno, tal como lo mencionó Jeremiah Willcock: http://ss64.com/nt/if.html - ¡ellos usan eso! Bien, pero ¿qué pasa con las comillas?

Nuevamente, respuesta corta: son "mágicos" - a veces las comillas dobles (dobles) se convierten en una comilla simple (doble). Y necesitan coincidir, para empezar.

Considere este pequeño guión:

@rem argq.bat
@echo off

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

:done
echo Done.

Vamos a probarlo:

C:\> argq bla bla
bla
bla
Done.

Parece funcionar. Pero ahora, cambiemos a la segunda marcha:

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

Boom Esto no se evaluó como verdadero, ni tampoco como falso. El guión MURIÓ. Si se suponía que debías apagar el reactor en algún momento, bueno, mala suerte. Ahora morirás como Harry Daghlian.

Puede pensar: está bien, los argumentos no pueden contener comillas. Si lo hacen, esto sucede.Incorrecto Aquí hay un consuelo:

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

Oh si. No te preocupes a veces esto va a funcionar.

Probemos con otro script:

@rem args.bat
@echo off

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

:done
echo Done.

Puede probar usted mismo que funciona bien para los casos anteriores. Esto es lógico: las comillas no tienen nada que ver con los corchetes, por lo que no hay magia aquí. Pero, ¿qué hay de condimentar los argumentos con corchetes?

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

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

No hubo suerte ahí. Los corchetes simplemente no pueden bloquear cmd.exeel analizador.

Volvamos a las citas malvadas por un momento. El problema estaba ahí, cuando la discusión terminó con una cita:

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

¿Qué pasa si paso solo:

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

El script no se ejecutará en absoluto. Lo mismo para args.bat:

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

Pero, ¿qué obtengo, cuando el número de "caracteres "coincide" (es decir, es par), en tal caso:

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

NICE - Espero que hayas aprendido algo sobre cómo.bat archivos dividen sus argumentos de línea de comando (SUGERENCIA: * No es exactamente como en bash). El argumento anterior contiene un espacio. Pero las citas no se eliminan automáticamente.

¿Y argq? ¿Cómo reacciona ante eso? Como era de esperar:

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

Entonces, piense antes de decir: "¿Sabes qué? Solo usa comillas. [Porque, para mí, esto se ve mejor]".

Editar

Recientemente, hubo comentarios sobre esta respuesta; bueno, los corchetes sqare "no pueden manejar" pasar argumentos entre comillas y tratarlos como si no estuvieran citados.

La sintaxis:

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

No es una virtud recién descubierta de las comillas dobles, sino una muestra de una característica clara de eliminar las comillas de la variable argumento, si el primer y último carácter es una comilla doble.

Esta "tecnología" funciona igual de bien con corchetes:

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

Fue útil señalar esto, así que también voté a favor de la nueva respuesta.

Finalmente, fanáticos de las comillas dobles, ¿existe un argumento de la forma ""en su libro o está en blanco? Solo preguntaba' ;)

Tomasz Gandor
fuente
1
Los corchetes [%1]==[-b]no coincidirán si arg se cita como run.bat "-b". Ver stackoverflow.com/a/46942471
wisbucky
Nota histórica: [%1]==[-b]y "%1"=="-b"eran los mismos para win 98 y scripts por lotes de sistemas MS / PC-DOS anteriores. Desde que win 2000 / NT introdujo una sintaxis if "%~1"=="-b"donde las comillas dobles tienen un significado especial, esa es la forma en que debe codificar los scripts, ya que proporciona una protección más sólida. Las comillas dobles escapan al significado de los caracteres especiales (try & | y% chars en su línea de comando). El 99,9% de los ejemplos funcionan con sintaxis de comillas dobles; su ejemplo argq bla2" "bla3es el único caso para justificar los corchetes. Las comillas dobles incrustadas son una receta para el desastre, solo digo
omita R
@SkipR: es por eso que en los sistemas de archivos de Windows, no puede tener estos caracteres especiales en los nombres. No tengo una prueba matemática, pero creo que simplemente NO todo puede ser citado (en el sentido de - hecho literalmente a través de alguna secuencia de escape, etc.) en el cmdshell. En otros sistemas, a veces se puede citar todo, incluido el carácter NUL. ( stackoverflow.com/questions/2730732/… ): esta pregunta solo muestra que necesita usar algún programa externo.
Tomasz Gandor
8

Además de las otras respuestas, que me suscribo, puede considerar usar el /Iinterruptor del IFcomando.

... el modificador / I, si se especifica, dice que se comparen cadenas que no distinguen entre mayúsculas y minúsculas.

puede ser de ayuda si desea dar a sus usuarios una flexibilidad que no distinga entre mayúsculas y minúsculas para especificar los parámetros.

IF /I "%1"=="-b" GOTO SPECIFIC
PENSILVANIA.
fuente
5

Estás comparando cadenas. Si se omite un argumento, se %1expande a un espacio en blanco para que los comandos se conviertan, IF =="-b" GOTO SPECIFICpor ejemplo, en un error de sintaxis. Envuelva sus cadenas entre comillas (o corchetes).

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
fuente
SI [% 1] == [/?] No está funcionando, pero yo sí SI [% 1] == [] o "% 1" == "", entonces funciona. De todos modos ahora puedo irme. Gracias por su rápida respuesta.
javauser71
5

En realidad, todas las demás respuestas tienen fallas. La forma más confiable es:

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

Explicación detallada:

El uso "%1"=="-b"se bloqueará por completo si se pasa un argumento con espacios y comillas. Este es el método menos confiable.

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

C:\> run.bat "a b"

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

Usar [%1]==[-b]es mejor porque no se bloqueará con espacios y comillas, pero no coincidirá si el argumento está entre comillas.

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

C:\> run.bat "-b"

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

El uso "%~1"=="-b"es el más confiable. %~1eliminará las comillas circundantes si existen. Por lo que funciona con y sin comillas, y también sin argumentos.

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
fuente
1
Este no es el final de los corchetes, como ve: IF [%~1]==[]- esto funciona, e incluso maneja "-b". Solo necesita poder pensar dentro del cuadro, eh, cuadrados [corchetes].
Tomasz Gandor
3

Recientemente he estado luchando con la implementación de cambios de parámetros complejos en un archivo por lotes, así que aquí está el resultado de mi investigación. Ninguna de las respuestas proporcionadas es completamente segura, ejemplos:

"%1"=="-?" no coincidirá si el parámetro está entre comillas (necesario para los nombres de archivo, etc.) o se bloqueará si el parámetro está entre comillas y tiene espacios (nuevamente, se ve a menudo en los nombres de archivo)

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

Cualquier combinación con corchetes [%1]==[-?]o [%~1]==[-?]fallará en caso de que el parámetro tenga espacios entre comillas:

@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 solución más segura propuesta "%~1"=="-?"se bloqueará con un parámetro complejo que incluye texto fuera de las comillas y texto con espacios dentro de las comillas:

@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 única forma de garantizar que se cubran todos los escenarios anteriores es usar EnableDelayedExpansion y pasar los parámetros por referencia (no por valor) usando variables. Entonces, incluso el escenario más complejo funcionará 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
fuente
0

El lote de Windows tiene la palabra clave DEFINED para hacer esto.

IF DEFINED %~1 foo
IF NOT DEFINED %~1 bar
Charles
fuente
Gracias David. No sé por qué no pudo haber un retorno de carro y una nueva línea entre IF y IF NOT. Ni siquiera me di cuenta.
Charles