Posso ter um bloco IF no arquivo de lote DOS?

96

Em um arquivo de lote DOS, só podemos ter 1 linha se o corpo da instrução? Acho que encontrei algum lugar que poderia usar ()para um bloco if, exatamente como o {}usado em linguagens de programação como C, mas não está executando as instruções quando tento fazer isso. Nenhuma mensagem de erro também. Este meu código:

if %GPMANAGER_FOUND%==true(echo GP Manager is up
goto Continue7
)
echo GP Manager is down
:Continue7

Estranhamente, nem "GP Manager is up" nem "GP Manager is down" são impressos quando executo o arquivo em lote.

Hugh Darling
fonte
Talvez isso pode ajudar: commandwindows.com/batchfiles-branching.htm
esaj
Sim, isso ajuda. DOS é uma merda. Se eu quiser usar várias instruções em if ou então, tenho que usar && entre as instruções? ou existe uma forma mais elegante?
Hugh Darling

Respostas:

139

Você pode, de fato, criar um bloco de instruções para executar após uma condicional. Mas você tem a sintaxe errada. Os parênteses devem ser usados ​​exatamente como mostrado:

if <statement> (
    do something
) else (
    do something else
)

No entanto, não acredito que haja qualquer sintaxe embutida para else-ifinstruções. Infelizmente, você precisará criar blocos aninhados de ifinstruções para lidar com isso.


Em segundo lugar, esse %GPMANAGER_FOUND% == trueteste parece muito suspeito para mim. Não sei como a variável de ambiente está definida ou como você está definindo, mas duvido muito que o código que você mostrou produzirá o resultado que você está procurando.


O código de exemplo a seguir funciona bem para mim:

@echo off

if ERRORLEVEL == 0 (
    echo GP Manager is up
    goto Continue7
)
echo GP Manager is down
:Continue7

Observe alguns detalhes específicos sobre meu código de amostra:

  • O espaço adicionado entre o final da declaração condicional e o parêntese de abertura.
  • Estou configurando @echo offpara não ver todas as instruções impressas no console à medida que são executadas e, em vez disso, ver apenas a saída daquelas que especificamente começam com echo.
  • Estou usando a ERRORLEVELvariável interna apenas como um teste. Leia mais aqui
Cody Gray
fonte
1
Melhor usar se% ERRORLEVEL% == 0, pois a outra variante é sempre verdadeira, porque IF ERRORLEVEL <N> é verdadeiro, se errorlevel for igual ou maior <N>, "==" são ignorados neste caso
jeb
@jeb: Acho que você não entendeu. Usar ERRORLEVELnão é a resposta para seu problema. Eu estava simplesmente postando um exemplo da sintaxe adequada. Qualquer forma é aceitável neste caso, assim como seria if 0 == 0ou qualquer outra expressão trivial. Mas, na verdade, certifique-se de entender a diferença entre a variável de ambiente %ERRORLEVEL%e a interna ERRORLEVELdo processador de comando. Raymond Chen explica isso muito bem aqui neste blog .
Cody Gray
Você pode ter um ELSE IF?
xagyg
1
Adicionando ao comentário de @ mythofechelon, mesmo um parêntese de fechamento aparentemente inócuo em uma instrução REM encerrará o bloco. por exemplo, jogar REM This is a comment (or so I thought)no IFbloco vai bagunçar você.
rkagerer
2
Tanto @mythofechelon quanto @rkagerer estão apontando problemas específicos de uma regra geral que as strings precisam ser citadas. Você nunca deve codificar IF %somevar%==example_string2 , deve ser sempre código para que o operando resolva IF "value_of_somevar"=="example_string2"para evitar que caracteres especiais em qualquer operando de string causem erros de sintaxe na IFinstrução. Os valores que você definir devem ser sempre executados como set "somevar=value_of_somevar" Essa sintaxe permite que você escape caracteres especiais em valores variáveis, Nota que eu não quero dizer set somevar="value_of_somevar"
Pular R
15

Logicamente, a resposta de Cody deve funcionar. No entanto, não acho que o prompt de comando lida com um bloco de código logicamente. Pela minha vida, não consigo fazer isso funcionar corretamente com mais do que um único comando dentro do bloco. No meu caso, testes extensivos revelaram que todos os comandos dentro do bloco estão sendo armazenados em cache e executados simultaneamente no final do bloco. É claro que isso não produz os resultados esperados. Aqui está um exemplo simplificado:

if %ERRORLEVEL%==0 (
set var1=blue
set var2=cheese
set var3=%var1%_%var2%
)

Isso deve fornecer var3 com o seguinte valor:

blue_cheese

mas, em vez disso, produz:

_

porque todos os 3 comandos são armazenados em cache e executados simultaneamente ao sair do bloco de código.

Consegui superar esse problema reescrevendo o bloco if para executar apenas um comando - goto - e adicionando alguns rótulos. É desajeitado e não gosto muito disso, mas pelo menos funciona.

if %ERRORLEVEL%==0 goto :error0
goto :endif

:error0
set var1=blue
set var2=cheese
set var3=%var1%_%var2%

:endif
usuario
fonte
8
O uso de expansão atrasada deve funcionar: use:set var3=!var1!_!var2!
Dracorat
4

Em vez dessa bagunça goto, tente usar o "e" comercial & ou o "e" comercial duplo && (condicional ao nível de erro 0) como separadores de comando.

Corrigi um trecho de script com este truque, para resumir, tenho três arquivos em lote, um que chama os outros dois depois de ter encontrado as letras que as unidades de backup externas foram atribuídas. Deixo o primeiro arquivo na unidade externa primária para que as chamadas para sua rotina de backup funcionem bem, mas as chamadas para o segundo exigem uma mudança de unidade ativa. O código abaixo mostra como corrigi-lo:

for %%b in (d e f g h i j k l m n o p q r s t u v w x y z) DO (
if exist "%%b:\Backup.cmd" %%b: & CALL "%%b:\Backup.cmd"
)
Louis
fonte
Por que diabos isso foi rejeitado? Isso é exatamente o que eu precisava.
ggb667
1
@ GCB667 - Para esclarecer, @Louis "escreveu uma" resposta "que não se relaciona com o problema de por que a declaração IF não estava funcionando para o autor do pôster original. Relacionava-se a uma resposta de" vinniejohnson "(que também omitiu o problema do pôster original) .
Pular R
1

Eu encontrei este artigo nos resultados retornados por uma pesquisa relacionada ao comando IF em um arquivo em lote e não pude resistir à oportunidade de corrigir o equívoco de que os blocos IF são limitados a comandos únicos. A seguir está uma parte de um script de comando de produção do Windows NT que é executado diariamente na máquina na qual estou redigindo esta resposta.

    if "%COPYTOOL%" equ "R" (
    WWLOGGER.exe "%APPDATA%\WizardWrx\%~n0.LOG" "Using RoboCopy to make a backup of %USERPROFILE%\My Documents\Outlook Files\*"
    %TOOLPATH% %SRCEPATH% %DESTPATH% /copyall %RCLOGSTR% /m /np /r:0 /tee
    C:\BIN\ExitCodeMapper.exe C:\BIN\ExitCodeMapper.INI[Robocopy] %TEMP%\%~n0.TMP %ERRORLEVEL%
) else (
    WWLOGGER.exe "%APPDATA%\WizardWrx\%~n0.LOG" "Using XCopy to make a backup of %USERPROFILE%\My Documents\Outlook Files\*"
    call %TOOLPATH%  "%USERPROFILE%\My Documents\Outlook Files\*" "%USERPROFILE%\My Documents\Outlook Files\_backups" /f /m /v /y
    C:\BIN\ExitCodeMapper.exe C:\BIN\ExitCodeMapper.INI[Xcopy] %TEMP%\%~n0.TMP %ERRORLEVEL%
)

Talvez os blocos de duas ou mais linhas se apliquem exclusivamente aos scripts de comando do Windows NT (arquivos .CMD), porque uma pesquisa no diretório de scripts de produção de um aplicativo restrito a arquivos batch da velha escola (.BAT) revelou apenas blocos de um comando . Como o aplicativo entrou em manutenção estendida (o que significa que não estou ativamente envolvido no suporte), não posso dizer se é porque não precisei de mais de uma linha ou não consegui fazê-los funcionar.

Independentemente disso, se o último for verdadeiro, há uma solução simples; mova as várias linhas para um arquivo em lote separado ou uma sub-rotina de arquivo em lote. Eu sei que este último funciona em ambos os tipos de scripts.

David A. Gray
fonte
0

Talvez um pouco tarde, mas espero que demônios:

@echo off 

if %ERRORLEVEL% == 0 (
msg * 1st line WORKS FINE rem You can relpace msg * with any othe operation...
goto Continue1
)
:Continue1
If exist "C:\Python31" (
msg * 2nd line WORKS FINE rem You can relpace msg * with any othe operation...
    goto Continue2
)
:Continue2
If exist "C:\Python31\Lib\site-packages\PyQt4" (  
msg * 3th line WORKS FINE rem You can relpace msg * with any othe operation...
    goto Continue3
)
:Continue3
msg * 4th line WORKS FINE rem You can relpace msg * with any othe operation...
    goto Continue4
)
:Continue4
msg * "Tutto a posto" rem You can relpace msg * with any othe operation...
pause
Vinniejohnson
fonte