Co oznacza łącznik w pliku wsadowym systemu Windows?

1

W szczególności mam problemy ze zrozumieniem łączników w następujących wierszach, które pochodzą z wikibooks

if not -%1-==-- echo Argument one provided
if -%1-==-- echo Argument one not provided & exit /b

Aby sprawdzić, czy zmienna istnieje lub jest zdefiniowana, są zasadniczo dwa sposoby, których nauczyłem się tutaj :

IF DEFINED MyVar (ECHO MyVar IS defined) ELSE (ECHO MyVar is NOT defined)

IF "%MyVar%"=="" (ECHO MyVar is NOT defined) ELSE (ECHO MyVar IS defined)

Więc co (1) łączniki wokół argumentu% 1 i (2) łączniki po znaku ==?

midnite
źródło
1
jeden z twoich komentarzy wspominał %%, który jest używany w pętli for w pliku wsadowym, takim jak %% f, nie dla parametrów wiersza polecenia wsadowego% 1% 2% 3. Z wiersza poleceń możesz to zrobić, for %1 in (*.*) do @echo %1a byłoby to dwuznaczne, aby zrobić to w pliku wsadowym, więc w przypadku instrukcji znajdujących się w pliku wsadowym użyj %%, ale parametry wsadowe (które są zawsze tylko w pliku wsadowym) to zawsze% 1 ,% 2 itd.
barlop
Drogi midnite: Jest rok 2015. Dlaczego nadal używasz języka programowania tak kiepskiego jak skrypty wsadowe? Możesz przełączyć się na VBScript, JScript, PowerShell lub jedną z wielu innych opcji .
niezapomniany
„Jednak wymagają one zainstalowania interpretera języka skryptowego, zanim będzie można go użyć” - bez szkody, aby dowiedzieć się więcej, szczególnie działa on natywnie na większości komputerów ;-)
midnite
1
@midnite Chyba wsadowo, istnieje limit liczby problemów, na które możesz natknąć się. Więc nauczyłem się przez lata, pytając i bawiąc się. I wydaje się, że są geniusze, którzy wymyślili rzeczy, które nie zostały zapisane w żadnych odnośnikach, kiedy robi się naprawdę trudny. Na przykład .. dave benham i jeb .. Myślę, że oba posty tutaj, a także na forum dostips .. A jeśli chodzi o odniesienie, jest oryginalny vfrazee.com/ms-dos/6.22/help, który pojawił się w DOSie podczas uruchamiania HELP.COM (możesz kliknąć np. JEŻELI następnie przykłady), a tam jest ss64.com/nt
barlop
1
te małe programy C mogą pomóc pokazać, jak programy dzielą rzeczy na parametry, aby pomóc w rozwiązywaniu problemów z cudzysłowami superuser.com/questions/944745/sed-command-with-apostrophe/... A jeśli kiedykolwiek zwariowałeś, to napisali jeb i dbenham posty o tym, jak działa interpreter wsadowy .. znalezione poprzez przetestowanie go, a nie inne referencje stackoverflow.com/questions/4094699/...
barlop

Odpowiedzi:

6

Rozważ to

C:\>if not -%1-==-- echo Argument one provided
Argument one provided

C:\>if not P%1P==PP echo Argument one provided
Argument one provided

Powinno być oczywiste, że znak minus / łącznik jest po prostu używany do ułatwienia wyznaczenia pustej wartości. Ten konkretny symbol nie ma specjalnego znaczenia w tym wyrażeniu - jest traktowany jak każdy inny nietypowy znak.

Możemy dodać spacje, aby wyjaśnić, że ==operator nie jest modyfikowany przez otaczające znaki

C:\>if not P%1P == PP echo Argument one provided
Argument one provided

Zasadniczo lepiej jest stosować konwencjonalne podejścia, które więcej osób zrozumie od razu (np. Użycie znaków cudzysłowu).

C:\>if not "%1"=="" echo Argument one provided
Argument one provided

W przypadku systemu DOS i być może wczesnych wersji systemu Windows uważam, że wystąpiły pewne problemy (których nie pamiętam) przy użyciu znaków cudzysłowu, które doprowadziły do ​​tego, że ludzie używali w ten sposób znaków do wydruku. Nie próbowałem przypadku, w którym% 1 zawiera na przykład znak cudzysłowu.

RedGrittyBrick
źródło
Widzę. Dziękuję bardzo. Czyli w gruncie rzeczy oznacza to konkatenację dwóch znaków przed i za zmienną, prawda? OTOH, próbowałem użyć definedsłowa kluczowego, aby sprawdzić, czy parametr istnieje. Oba IF DEFINED %1i IF DEFINED %%1wydają się nie działać. Czy dałbyś mi jakieś wskazówki?
midnite
Piszesz „znak minus / myślnik jest po prostu używany do uproszczenia oznaczenia pustej wartości” <--- słowo „upraszczaj” prawdopodobnie nie jest dobrym słowem do użycia, ponieważ nie tylko upraszcza ( jakiekolwiek uproszczenie oznaczałoby). Ale jak wiadomo, zapobiega to błędom, gdy nie podano żadnego argumentu.
barlop
@barlop: Dzięki za komentarz. Odpowiedź edytowana.
RedGrittyBrick
Dobra edycja, ale na końcu napisałeś: „Z DOS i być może wczesnymi wersjami Windows, myślę, że były pewne problemy (których nie pamiętam) z użyciem znaków cudzysłowu” <- Nadal są. ponownie używam „% 1”, zobacz moją odpowiedź. Początkowo powiedziałem, że cytaty były świetne w okolicy% 1, potem supercat, skomentował i poprawiłem to.
barlop
Piszesz „nie próbowałem przypadku, w którym% 1 zawiera na przykład znak cudzysłowu”. <- Jeśli użytkownik je dostarczy, a ty nie zrobisz "% 1", to dobrze. Jeśli użytkownik je dostarczy i dodasz je „% 1”, to nie w porządku
barlop
4

Jest to ważne, gdy używasz% 1 do umieszczenia czegoś wokół niego, aby zapobiec zerwaniu pliku wsadowego, gdy% 1 jest pusty, ponieważ% 1 nie jest zmienną, zostaje podstawiona wartością, jak np. Wstrzyknięcie SQL jako przykład wstrzyknięcia wsadowego i gdy wartość jest niczym, a% 1 jest w JEŻELI, wtedy zostaje uszkodzony kod. if %1==""staje się if == ""i daje błąd.

Jeśli chodzi o to, dlaczego jeśli zdefiniowane nie działa na% 1,% 1 jest wartością, a nie zmienną, więc zdefiniowane tam nie działa. Aby kod działający dla% 1 był pusty, potrzebujesz kodu, który nie ulegnie uszkodzeniu, gdy% 1 zostanie zastąpiony niczym. Spróbuj if "%1"=="" lub spróbujif [%1]==[]

Można powiedzieć, że% 1 wygląda trochę myląco, nie wygląda mi to na dobrą konwencję! Technicznie można nawet zrobić if a%1==a%1 albo if %1a==%1aale konwencja wydaje się być[]

Możesz użyć cudzysłowów, [] lub dowolnych znaków. Ale jak zauważył supercat w komentarzu, cytaty nie są dobrym pomysłem w przypadku% 1. (Ponieważ jeśli% 1 zawiera spacje, użytkownik dołącza cudzysłowy do tego, co zostaje przekazane jako% 1, a jeśli jest% w spacji i w pliku wsadowym wstawiasz cudzysłowy wokół% 1, cytaty zostaną anulowane i niecytowane miejsce spowoduje błąd).

Jeśli robisz IF w wierszu poleceń i nie testujesz żadnej zmiennej, nie masz% 1 i nawet nie potrzebujesz []. Powiedziałbyś IF "a b c"=="a b c" echo a lub IF a==b echo a Jeśli w pliku wsadowym często masz% 1, a zamiast cudzysłowów wokół% 1, użyj np. Jednego lub dwóch znaków np. [%1]I użyj cudzysłowów, jeśli chcesz zachować spacje i nie jest to% 1 egeg IF [%1]==[a]lub IF [%1]==["a b"] echo aNie rób, "%1"ponieważ% 1 może już zawierać cytaty, które zostaną anulowane, a następnie, jeśli% 1 ma spację, instrukcja if łamie się.

Jeśli byłeś w linii poleceń i testowałeś zmienną, to zależy od tego, czy zmienna ma cudzysłowy. Możesz spojrzeć na zawartość.

Zmienna może mieć spację i nie zawierać cudzysłowów.

Tak więc w tym konkretnym przypadku wiersza polecenia, umieszczanie cudzysłowów w okolicach% a% nie spowoduje podwójnego cudzysłowu, a jeśli chcesz przetestować względem „a b”, musisz wstawić cudzysłowy wokół% a%

C:\>set a=a b

C:\>echo %a%
a b

C:\>IF %a%=="a b" echo sdf
b=="a b" was unexpected at this time.

C:\>IF "%a%"=="a b" echo sdf
sdf

So ^^^ we want "%a%"

Podczas gdy jeśli% a% zawierałby cudzysłowy, byłby to inny przypadek

C:\>set a="a b"

C:\>echo %a%
"a b"

C:\>IF %a%=="a b" echo a
a

C:\>IF "%a%"=="a b" echo a
b""=="a b" was unexpected at this time.

C:\>

^^^^ So there we want %a% without quotes around it.

Wszystko więc zależy od tego, czy zmienna lub parametr zawiera cudzysłowy. Jeśli% 1 ma spacje, będzie zawierał cudzysłowy. Wiemy więc, że gdybyśmy porównali% 1 z „a b”, to w nie zrobiłby „% 1”. A gdyby% 1 nie zawierał cudzysłowów, nie zawierałby spacji, więc nie zrobilibyśmy „% 1”. Myślę, że nigdy nie chciałbyś robić „% 1”. Tak więc, jeśli% 1 zawiera spacje, w% 1 pojawią się cudzysłowy, a spacje zostaną już zachowane.

Przekreśliłem poniżej w świetle komentarza superkata. I dodałem więcej do mojego postu powyżej.

Cytaty są najlepsze w okolicach% 1, a nie [] lub niektórych znaków, takich jak A lub -, ponieważ na przykład jeśli użyjesz [], to nie zachowa spacji

C: \> if [dab] == [dab] echo sdf

w tym czasie było nieoczekiwane.

Powiedz, if "d a b"że to zadziała. Więc if "%1"jest lepszy niż inne postacie takie jak if [%1]lub a%1alub-%1

barlop
źródło
2
Jedynym sposobem %1będzie rozwinięcie się do czegoś zawierającego spacje, jeśli argument zawiera znaki cudzysłowu. W takim przypadku otoczenie %1ze znakami cudzysłowu spowoduje zepsute zachowanie, a otoczenie go czymś innym powinno działać.
supercat
2
Co jeśli cytowany argument zawiera spacje?
supercat
1
@supercat ah widzę, dobrze zauważony. if "" 2""==""2"" echo azawodzi. A na wypadek, gdyby nikt nie wiedział ... Efektem ""będzie włączenie lub wyłączenie cytowania.
barlop
1
@midnite ma pewne podobieństwo do konkatenacji, którą widzisz w bardziej zaawansowanych językach, ale myślę, że funkcjonalnie nie tak bardzo, bo w java itp., konkatenacja składa się z dwóch oddzielnych jednostek, nawet jeśli wykonujesz „asdf” + „asdf”. Natomiast w cmd "asdf""asdf"nie łączy dwóch osobnych obiektów. Pierwszy „oznacza włączenie trybu, w którym zachowane są spacje i niektóre inne znaki. Następny” oznacza wyłączenie tego trybu. Następny włącza. Możesz więc powiedzieć „asdf asdf” lub powiedzieć „ asdf" "asdf Więc 2""nie powinno to wyglądać zbyt skomplikowane”. (ale czasem zastanawianie się, jak działa cmd / partia, jest trudne)
barlop
1
@midnite także Wątpię, aby plik wsadowy (ogólnie) rozróżniał ciągi i liczby, chociaż niektóre polecenia lub funkcje w poleceniu tak. To, czy 2 jest liczbą, czy łańcuchem, zależy od interpretacji. Jeśli powiesz, że echo 2nie ma konwersji 2 na ciąg. Przypuszczam, że technicznie z komputerami wszystko to jest zakodowane (nie powiem znaków) zawijasy / glify. Niektórzy mogą spojrzeć na prezentację, jeśli są cytatami lub nie, a następnie potraktować ją odpowiednio jako liczbę (do obliczeń) lub ciąg znaków (w celu posortowania ich alfabetycznie). Lub tak jak zakodowane glify są to liczby lub ciągi znaków.
barlop
1

Nie jestem pewien, czy to rozumiesz, więc pozwól mi zobaczyć, czy mogę to uprościć.

Załóżmy, że plik wsadowy otrzymuje wartość %1z wiersza poleceń i chcesz sprawdzić, czy jest to „kot” czy „pies”. Możesz to sprawdzić:

if %1 == cat goto CAT
if %1 == dog goto DOG
REM Default: Complain about no dog or cat
goto OOPS
:CAT
echo I'm a cat!
REM Successful, so skip to end
goto END
:DOG
echo I'm a dog!
goto END
:OOPS
echo I didn't see a cat or dog!
REM This just falls through to the end
:END

%1 zastępuje się tekstem kot lub pies (powiedzmy pies), więc tłumacz naprawdę to widzi:

if dog == cat goto CAT
if dog == dog goto DOG

Ale jeśli osoba uruchamiająca skrypt nie podała wartości w wierszu poleceń, interpreter zobaczy to:

if  == cat goto CAT
if  == dog goto DOG

To jest niepoprawna składnia i spowoduje błąd. Konwencja polega więc na tym, aby dołączyć 1 lub więcej znaków i najpierw sprawdzić brak zmiennej, coś takiego:

if %1* == * goto OOPS
REM If no value passed in, this is seen as  if * == *  which evaluates to true
if %1 == cat goto CAT
if %1 == dog goto DOG
goto END
:CAT
echo I'm a cat!
goto END
:DOG
echo I'm a dog!
goto END
:OOPS
echo You were supposed to include a type of pet!
:END

Jeśli %1nic nie zostanie ocenione, dodatkowe znaki są nadal dostępne, aby zachować poprawną składnię. Używam *, ale często pojawiają się cytaty lub wykrzykniki, takie jak "%1"lub %1!, a także łączniki, takie jak --%1lub -%1-itp.

Człowieku, nie mogę uwierzyć, że wciąż to wszystko pamiętam. :-) Mam nadzieję, że to pomoże!

furry_marmot
źródło
Napisałeś „Ale jeśli osoba uruchamiająca skrypt nie zawierała zmiennej”, <- możesz mieć na myśli „wartość”, ponieważ jest to bardziej wartość niż zmienna. Przekazuje dane, może można powiedzieć wartość. A jeśli chodzi o sposób, w jaki to jest przekazywane, (w programowaniu niektórych bardziej zaawansowanych języków możesz mieć „pass by value” lub „pass by reference”. Myślę, że można by powiedzieć, że to jest przekazywane przez wstrzyknięcie!
barlop
„możesz oznaczać„ wartość [zamiast zmiennej] ”… Ups! Masz rację!
furry_marmot