Como verificar o parâmetro da linha de comando no arquivo “.bat”?

103

Meu sistema operacional é o Windows Vista. Eu preciso ter um arquivo ".bat" onde preciso verificar se o usuário insere algum parâmetro de linha de comando ou não. Se sim, então se o parâmetro for igual a -bentão farei algo, caso contrário, sinalizarei "Entrada inválida". Se o usuário não inserir nenhum parâmetro de linha de comando, farei algo. Eu criei o seguinte arquivo .bat. Ele funciona para os casos -be não é igual a eles -b- mas falha quando o usuário não passa nenhum parâmetro de linha de comando.

Sempre recebo erros:

GOTO was unexpected at this time.

Alguém pode me dizer o que estou fazendo de errado aqui?


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
fonte
Se você adicionar colchetes (como na GOTO BLANKlinha) às outras duas IFdeclarações, isso resolve o problema?
Jeremiah Willcock

Respostas:

141

Você precisa verificar se o parâmetro está em branco: if "%~1"=="" goto blank

Depois de fazer isso, faça um if / else alterne para -b: if "%~1"=="-b" (goto specific) else goto unknown

Colocar os parâmetros entre aspas facilita a verificação de itens como parâmetros em branco / vazios / ausentes. "~" garante que as aspas duplas sejam removidas se estiverem no argumento da linha de comando.

afrazier
fonte
Isso funciona!! Apenas "else" não é aceito. Recebo o erro: 'else' não é reconhecido como um comando interno ou externo, programa operável ou arquivo em lote. Portanto, adicionei outro IF para o caso "diferente de -b". Obrigado pela resposta rápida.
javauser71 de
7
O ELSE tem que estar na mesma linha que o IF, ou tem que estar logo após um colchete
jeb
4
Isso não parece funcionar para mim se% 1 contiver espaços, o que pode ser o caso se for o caminho completo para um executável. Veja a resposta de Jeremiah Willcock para uma solução que funciona até mesmo para parâmetros com espaços em seus valores.
Mark A. Fitzgerald
não será aceito se o seu argumento for a File, nesse caso você deve verificar apenas existou not exist. É por isso que seus argumentos devem ser bem definidos ou simplesmente usar powershell ou vbScript (se você estiver nos anos 80 ..)
1
Isso falha para run.bat "a b". "%1"==""falha se o arg tiver um espaço. Consulte stackoverflow.com/a/46942471
wisbucky
27

Consulte http://ss64.com/nt/if.html para obter uma resposta; o comando é IF [%1]==[] GOTO NO_ARGUMENTou semelhante.

Jeremiah Willcock
fonte
1
Não só isso TAMBÉM funciona! Simplesmente funciona, ao contrário de "%1"=="". Eu tenho que elaborar sobre isso em minha própria resposta.
Tomasz Gandor
1
isso será interrompido quando% 1 for citado, por exemplo foo.bat "1st parameter" 2nd_param. Consulte stackoverflow.com/questions/2541767/…
matt wilkie
Usar [%1]==[-b]não corresponderá se arg estiver entre aspas. Exemplo run.bat "-b". Consulte stackoverflow.com/a/46942471
wisbucky
20

A resposta curta - use colchetes:

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

ou (quando você precisar lidar com argumentos citados, consulte a edição abaixo):

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

Por quê? você pode perguntar. Bem, assim como Jeremiah Willcock mencionou: http://ss64.com/nt/if.html - eles usam isso! OK, mas o que há de errado com as aspas?

Novamente, uma resposta curta: eles são "mágicos" - às vezes as aspas duplas são convertidas em aspas simples (duplas). E eles precisam combinar, para começar.

Considere este pequeno script:

@rem argq.bat
@echo off

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

:done
echo Done.

Vamos testar:

C:\> argq bla bla
bla
bla
Done.

Parece funcionar. Mas agora, vamos mudar para a segunda marcha:

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

Boom Isso não foi avaliado como verdadeiro, nem foi avaliado como falso. O script MORREU. Se você deveria desligar o reator em algum ponto da linha, bem - azar. Você agora vai morrer como Harry Daghlian.

Você pode pensar - OK, os argumentos não podem conter aspas. Se o fizerem, isso acontece. Errado Aqui está um consolo:

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

Oh sim. Não se preocupe - às vezes isso vai funcionar.

Vamos tentar outro script:

@rem args.bat
@echo off

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

:done
echo Done.

Você pode testar a si mesmo, se funciona bem para os casos acima. Isso é lógico - as aspas não têm nada a ver com colchetes, então não há mágica aqui. Mas e quanto a apimentar os argumentos com colchetes?

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

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

Sem sorte aí. Os colchetes simplesmente não podem sufocar cmd.exeo analisador.

Vamos voltar às citações malignas por um momento. O problema estava lá, quando a discussão terminou com uma citação:

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

E se eu passar apenas:

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

O script não será executado. O mesmo para args.bat:

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

Mas o que eu obtenho, quando o número de "-caracteres "corresponde" (ou seja, - é par), em tal caso:

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

NICE - Espero que você tenha aprendido algo sobre como os .batarquivos dividem seus argumentos de linha de comando (DICA: * Não é exatamente como no bash). O argumento acima contém um espaço. Mas as aspas não são retiradas automaticamente.

E argq? Como isso reage a isso? Previsivelmente:

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

Então - pense antes de dizer: "Sabe o quê? Basta usar aspas. [Porque, para mim, isso parece melhor]".

Editar

Recentemente, houve comentários sobre essa resposta - bem, os colchetes "não conseguem lidar" com a passagem de argumentos citados e tratando-os como se não estivessem citados.

A sintaxe:

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

Não é uma virtude recém-descoberta das aspas duplas, mas uma exibição de uma característica interessante de retirar aspas da variável de argumento, se o primeiro e o último caractere forem aspas duplas.

Essa "tecnologia" funciona tão bem com colchetes:

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

Foi útil apontar isso, então também votei positivamente na nova resposta.

Finalmente, fãs de aspas duplas, ""existe um argumento da forma em seu livro ou está em branco? Apenas perguntando' ;)

Tomasz Gandor
fonte
1
Os colchetes [%1]==[-b]não corresponderão se arg estiver entre aspas run.bat "-b". Consulte stackoverflow.com/a/46942471
wisbucky
Historicamente, observe: [%1]==[-b]e "%1"=="-b"eram os mesmos para os scripts em lote dos sistemas Win 98 e MS / PC-DOS anteriores. Desde que o win 2000 / NT introduziu a sintaxe if "%~1"=="-b"onde as aspas duplas têm um significado especial, essa é a maneira como você deve codificar scripts, pois fornece uma proteção mais robusta. As aspas duplas escapam ao significado dos caracteres especiais (tente & | e% chars em sua linha de comando). 99,9% dos exemplos funcionam com sintaxe de aspas duplas - seu exemplo argq bla2" "bla3é apenas um caso para justificar colchetes. Aspas duplas incorporadas são uma receita para o desastre - basta dizer
Pule R
@SkipR - é por isso que nos sistemas de arquivos do Windows, você não pode ter esses caracteres especiais nos nomes. Não tenho uma prova matemática, mas acho que simplesmente NÃO tudo pode ser citado (no sentido de - feito literalmente por meio de alguma sequência de escape etc.) no cmdshell. Em outros sistemas, às vezes você pode citar tudo, incluindo o caractere NUL. ( stackoverflow.com/questions/2730732/… ) - esta questão apenas mostra, você precisa usar algum programa externo.
Tomasz Gandor
8

Além das outras respostas, que assino, você pode considerar o uso da /Iopção de IFcomando.

... a opção / I, se especificada, diz para fazer comparações de strings que não diferenciam maiúsculas de minúsculas.

pode ser útil se você quiser dar flexibilidade não sensível a maiúsculas e minúsculas aos seus usuários para especificar os parâmetros.

IF /I "%1"=="-b" GOTO SPECIFIC
PA.
fonte
5

Você está comparando strings. Se um argumento for omitido, %1expande para um espaço em branco para que os comandos se tornem, IF =="-b" GOTO SPECIFICpor exemplo (o que é um erro de sintaxe). Coloque suas strings entre aspas (ou colchetes).

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
fonte
SE [% 1] == [/?] Não está funcionando, mas eu faço SE [% 1] == [] ou "% 1" == "", então funciona. De qualquer forma, agora posso ir. Obrigado pela sua resposta rápida.
javauser71
5

Na verdade, todas as outras respostas têm falhas. A maneira mais confiável é:

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

Explicação detalhada:

O uso "%1"=="-b"irá travar se passar argumentos com espaços e aspas. Este é o método menos confiável.

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

C:\> run.bat "a b"

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

Usar [%1]==[-b]é melhor porque não travará com espaços e aspas, mas não corresponderá se o argumento estiver entre aspas.

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

C:\> run.bat "-b"

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

Usar "%~1"=="-b"é o mais confiável. %~1removerá as aspas se elas existirem. Portanto, ele funciona com e sem aspas e também sem 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
fonte
1
Isso não é o fim dos colchetes, você vê: IF [%~1]==[]- isso funciona, e até controla "-b". Você só precisa ser capaz de pensar dentro da caixa, erm, quadrado [colchetes].
Tomasz Gandor
3

Tenho lutado recentemente com a implementação de opções de parâmetro complexas em um arquivo em lote, então aqui está o resultado de minha pesquisa. Nenhuma das respostas fornecidas é totalmente segura, exemplos:

"%1"=="-?" não corresponderá se o parâmetro estiver entre aspas (necessário para nomes de arquivos etc.) ou travará se o parâmetro estiver entre aspas e tiver espaços (novamente, frequentemente visto em nomes de arquivo)

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

Qualquer combinação com colchetes [%1]==[-?]ou [%~1]==[-?]falhará caso o parâmetro tenha espaços entre aspas:

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

A solução mais segura proposta "%~1"=="-?"irá travar com um parâmetro complexo que inclui texto fora das aspas e texto com espaços entre aspas:

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

A única maneira de garantir que todos os cenários acima sejam cobertos é usar EnableDelayedExpansion e passar os parâmetros por referência (não por valor) usando variáveis. Então, mesmo o cenário mais complexo funcionará bem:

@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
fonte
0

O lote do Windows possui a palavra-chave DEFINED para fazer isso.

IF DEFINED %~1 foo
IF NOT DEFINED %~1 bar
Charles
fonte
Obrigado David. Não sei por que não houve um retorno de carro e uma nova linha entre IF e IF NOT. Eu nem percebi.
Charles