Czy mogę mieć blok IF w pliku wsadowym DOS?

97

W pliku wsadowym DOS możemy mieć tylko 1 linię, jeśli treść instrukcji? Myślę, że znalazłem miejsce, którego mógłbym użyć ()dla bloku if, takiego jak {}używany w językach programowania podobnych do C, ale nie wykonuje instrukcji, gdy próbuję tego. Brak komunikatu o błędzie. To mój kod:

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

O dziwo, po uruchomieniu pliku wsadowego nie jest drukowany komunikat „GP Manager nie działa” ani „GP Manager nie działa”.

Hugh Darling
źródło
Tak, to pomaga. DOS jest do bani. Jeśli chcę używać wielu instrukcji w if lub jeszcze, muszę używać && między instrukcjami? czy jest bardziej elegancki sposób?
Hugh Darling

Odpowiedzi:

141

Rzeczywiście, możesz umieścić utworzyć blok instrukcji do wykonania po warunku. Ale masz niewłaściwą składnię. Nawiasy należy stosować dokładnie tak, jak pokazano:

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

Nie wierzę jednak, że istnieje jakaś wbudowana składnia else-ifinstrukcji. Będziesz niestety musiał utworzyć zagnieżdżone bloki ifinstrukcji, aby sobie z tym poradzić.


Po drugie, ten %GPMANAGER_FOUND% == truetest wydaje mi się bardzo podejrzany. Nie wiem, na co jest ustawiona zmienna środowiskowa ani jak ją ustawiasz, ale bardzo wątpię, czy kod, który pokazałeś, da wynik, którego szukasz.


Poniższy przykładowy kod działa dobrze dla mnie:

@echo off

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

Zwróć uwagę na kilka szczegółowych informacji na temat mojego przykładowego kodu:

  • Spacja dodana między końcem instrukcji warunkowej a nawiasem otwierającym.
  • Ustawiam się, @echo offaby nie widzieć wszystkich instrukcji wyświetlanych na konsoli podczas ich wykonywania, a zamiast tego wyświetlać tylko wyniki tych, które konkretnie zaczynają się od echo.
  • Używam wbudowanej ERRORLEVELzmiennej tylko jako testu. Przeczytaj więcej tutaj
Cody Gray
źródło
1
Lepiej użyć, jeśli% ERRORLEVEL% == 0, ponieważ drugi wariant jest zawsze prawdziwy, ponieważ JEŻELI ERRORLEVEL <N> jest prawdziwe, jeśli poziom błędu jest równy lub większy <N>, w tym przypadku "==" są ignorowane
jeb
@jeb: Myślę, że mogłeś przegapić sedno. Używanie ERRORLEVELnie jest odpowiedzią na jego problem. Po prostu zamieszczałem przykład właściwej składni. Każda forma jest w tym przypadku akceptowalna, tak samo jak byłaby if 0 == 0lub każde inne trywialne wyrażenie. Ale rzeczywiście, upewnij się, że rozumiesz różnicę między zmienną środowiskową %ERRORLEVEL%a wewnętrzną ERRORLEVELczęścią procesora poleceń. Raymond Chen ładnie wyjaśnia to na tym blogu .
Cody Grey
Czy możesz mieć INNE JEŚLI?
xagyg
1
Dodając do komentarza @ mythofechelon, nawet pozornie nieszkodliwy nawias zamykający w instrukcji REM zakończy blok. np. rzucenie REM This is a comment (or so I thought)się w IFblok spowoduje zepsucie.
rkagerer
2
Zarówno @mythofechelon, jak i @rkagerer wskazują na konkretne kwestie związane z ogólną zasadą, że ciągi znaków muszą być cytowane. Nigdy nie powinieneś kodować IF %somevar%==example_string2 , zawsze powinien to być kod, więc operand rozwiązuje się tak, IF "value_of_somevar"=="example_string2aby uniknąć znaków specjalnych w którymkolwiek z argumentów łańcuchowych powodujących błędy składniowe w IFinstrukcji. Ustawiane wartości powinny być zawsze wykonywane, ponieważ set "somevar=value_of_somevar" Składnia ta pozwala na uniknięcie znaków specjalnych w wartościach zmiennych, Uwaga że nie mam na myśli set somevar="value_of_somevar"
Pomiń R
15

Logicznie rzecz biorąc, odpowiedź Cody'ego powinna działać. Jednak nie sądzę, aby wiersz polecenia logicznie obsługiwał blok kodu. Przez całe życie nie mogę sprawić, żeby to działało poprawnie z więcej niż jednym poleceniem w bloku. W moim przypadku obszerne testy wykazały, że wszystkie polecenia w bloku są buforowane i wykonywane jednocześnie na końcu bloku. To oczywiście nie daje oczekiwanych rezultatów. Oto nadmiernie uproszczony przykład:

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

To powinno zapewnić VAR3 z następujących wartości:

blue_cheese

ale zamiast tego daje:

_

ponieważ wszystkie 3 polecenia są buforowane i wykonywane jednocześnie po wyjściu z bloku kodu.

Udało mi się rozwiązać ten problem, ponownie pisząc blok if, aby wykonać tylko jedno polecenie - goto - i dodając kilka etykiet. Jest niezgrabny i nie bardzo mi się to podoba, ale przynajmniej działa.

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

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

:endif
Nacięcie
źródło
8
Używanie opóźnionej ekspansji powinno działać: użyj:set var3=!var1!_!var2!
Dracorat
4

Zamiast tego „goto bałagan” spróbuj użyć znaku ampersand & lub podwójnego znaku ampersand && (warunek poziomu błędu 0) jako separatorów poleceń.

Naprawiłem fragment skryptu za pomocą tej sztuczki, podsumowując, mam trzy pliki wsadowe, jeden, który wywołuje pozostałe dwa po znalezieniu liter, które zostały przypisane do zewnętrznych dysków kopii zapasowych. Zostawiam pierwszy plik na głównym dysku zewnętrznym, więc wywołania jego procedury tworzenia kopii zapasowych działały dobrze, ale wywołania drugiego wymagały zmiany aktywnego dysku. Poniższy kod pokazuje, jak to naprawiłem:

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
źródło
Dlaczego u licha jest to odrzucane? Właśnie tego potrzebowałem.
ggb667
1
@ GCB667 - Aby wyjaśnić, @Louis "napisał" odpowiedź ", która nie dotyczy problemu, dlaczego stwierdzenie IF nie działa dla oryginalnego plakatu. Dotyczyło to odpowiedzi" vinniejohnsona "(która również pominęła problem z oryginalnymi plakatami) .
Skip R
1

Natknąłem się na ten artykuł w wynikach zwróconych przez wyszukiwanie związane z poleceniem IF w pliku wsadowym i nie mogłem oprzeć się możliwości poprawienia błędnego przekonania, że ​​bloki IF są ograniczone do pojedynczych poleceń. Poniżej znajduje się część produkcyjnego skryptu poleceń systemu Windows NT, który jest uruchamiany codziennie na komputerze, na którym tworzę tę odpowiedź.

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

Być może bloki dwóch lub więcej wierszy dotyczą wyłącznie skryptów poleceń systemu Windows NT (plików .CMD), ponieważ przeszukanie katalogu skryptów produkcyjnych aplikacji, które jest ograniczone do plików wsadowych starej szkoły (.BAT), ujawniło tylko bloki jednego polecenia . Ponieważ aplikacja przeszła w rozszerzoną konserwację (co oznacza, że ​​nie jestem aktywnie zaangażowana we wspieranie jej), nie mogę powiedzieć, czy to dlatego, że nie potrzebowałem więcej niż jednej linii, czy też nie mogłem sprawić, by działały.

Niezależnie od tego, jeśli to ostatnie jest prawdą, istnieje proste obejście; przenieść wiele wierszy albo do oddzielnego pliku wsadowego, albo do podprocedury pliku wsadowego. Wiem, że ta ostatnia działa w obu rodzajach skryptów.

David A. Gray
źródło
0

Może trochę późno, ale mam nadzieję, że to piekło:

@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
źródło