Natrafiłem na ss64.com, który zapewnia dobrą pomoc dotyczącą pisania skryptów wsadowych, które będzie uruchamiał interpreter poleceń systemu Windows.
Jednak nie udało mi się znaleźć dobrego wyjaśnienia gramatyki skryptów wsadowych, tego, jak rzeczy się rozszerzają lub nie, ani jak uciec od rzeczy.
Oto przykładowe pytania, których nie udało mi się rozwiązać:
- Jak zarządzany jest system ofert? Zrobiłem TinyPerl skryptu
(foreach $i (@ARGV) { print '*' . $i ; }
), opracowano go i nazwał go w ten sposób:my_script.exe "a ""b"" c"
→ wyjście jest*a "b*c
my_script.exe """a b c"""
→ wyślij to*"a*b*c"
- Jak działa wewnętrzne
echo
polecenie? Co jest rozwinięte w tym poleceniu? - Dlaczego muszę używać
for [...] %%I
w skryptach plików, alefor [...] %I
w sesjach interaktywnych? - Jakie są postacie ucieczki i w jakim kontekście? Jak uciec przed znakiem procentu? Na przykład, jak mogę
%PROCESSOR_ARCHITECTURE%
dosłownie echo ? Okazało się, żeecho.exe %""PROCESSOR_ARCHITECTURE%
działa, czy jest lepsze rozwiązanie? - Jak
%
dopasowują się pary ? Przykład:set b=a
,echo %a %b% c%
→%a a c%
set a =b
,echo %a %b% c%
→bb c%
- Jak upewnić się, że zmienna jest przekazywana do polecenia jako pojedynczy argument, jeśli ta zmienna zawiera podwójne cudzysłowy?
- Jak przechowywane są zmienne podczas korzystania z
set
polecenia? Na przykład, jeśli to zrobięset a=a" b
iecho.%a%
otrzymama" b
. Jeśli jednak skorzystamecho.exe
z UnxUtils, otrzymama b
. Jak to się%a%
rozwija w inny sposób?
Dziękuję za wasze światła.
Odpowiedzi:
Przeprowadziliśmy eksperymenty, aby zbadać gramatykę skryptów wsadowych. Zbadaliśmy również różnice między trybem wsadowym a trybem wiersza poleceń.
Parser wiersza wsadu:
Oto krótki przegląd faz w parserze linii pliku wsadowego:
Faza 0) Linia odczytu:
Faza 1) Procentowa ekspansja:
Faza 2) Przetwarzaj znaki specjalne, tokenizuj i twórz buforowany blok poleceń: jest to złożony proces, na który wpływają takie rzeczy, jak cudzysłowy, znaki specjalne, ograniczniki tokenów i znaki specjalne.
Faza 3) Powtórz przeanalizowane polecenie (polecenia) Tylko wtedy, gdy blok poleceń nie rozpoczął się
@
, a funkcja ECHO była WŁĄCZONA na początku poprzedniego kroku.Faza 4)
%X
Rozszerzenie zmiennej FOR : Tylko wtedy, gdy polecenie FOR jest aktywne i polecenia po DO są przetwarzane.Faza 5) Opóźniona ekspansja: Tylko jeśli opóźniona ekspansja jest włączona
Faza 5.3) Przetwarzanie potoku : tylko wtedy, gdy polecenia są po obu stronach rury
Faza 5.5) Wykonaj przekierowanie:
Faza 6) Przetwarzanie wywołania / podwojenie karetki: Tylko jeśli token polecenia to CALL
Faza 7) Wykonaj: Polecenie jest wykonywane
Oto szczegóły dla każdej fazy:
Zauważ, że fazy opisane poniżej to tylko model działania parsera wsadowego. Rzeczywiste wewnętrzne funkcje cmd.exe mogą nie odzwierciedlać tych faz. Ale ten model jest skuteczny w przewidywaniu zachowania skryptów wsadowych.
Faza 0) Czytaj linię: Odczytaj najpierw linię wejściową
<LF>
.<Ctrl-Z>
(0x1A) jest odczytywane jako<LF>
(LineFeed 0x0A)<Ctrl-Z>
, działa jako samo - to nie przekształca się<LF>
Faza 1) Procentowa ekspansja:
%%
zostaje zastąpiony pojedynczym%
%*
,%1
,%2
, itd.)%var%
, jeśli var nie istnieje, zastąp je niczym<LF>
nie wewnątrz%var%
rozwijaniaFaza 2) Przetwarzaj znaki specjalne, tokenizuj i stwórz buforowany blok poleceń: jest to złożony proces, na który wpływają takie rzeczy, jak cudzysłowy, znaki specjalne, ograniczniki tokenów i znaki daszka. Poniżej przedstawiono przybliżenie tego procesu.
Istnieją koncepcje, które są ważne na tym etapie.
<space>
<tab>
;
,
=
<0x0B>
<0x0C>
i<0xFF>
kolejne ograniczniki tokenów są traktowane jako jeden - między ogranicznikami tokenów nie ma pustych tokenów
Następujące znaki mogą mieć specjalne znaczenie w tej fazie, w zależności od kontekstu:
<CR>
^
(
@
&
|
<
>
<LF>
<space>
<tab>
;
,
=
<0x0B>
<0x0C>
<0xFF>
Spójrz na każdą postać od lewej do prawej:
<CR>
to usuń go, jakby nigdy go tam nie było (z wyjątkiem dziwnego zachowania przekierowania )^
), następny znak jest zmieniany, a uciekający znak jest usuwany. Postacie, którym uciekł, tracą wszelkie specjalne znaczenie (z wyjątkiem<LF>
)."
), przełącz flagę quote. Jeśli flaga cudzysłowu jest aktywna, to tylko"
i<LF>
są specjalne. Wszystkie inne znaki tracą swoje specjalne znaczenie, dopóki następny cytat nie wyłączy flagi cytatu. Nie można uciec od notowania zamykającego. Wszystkie cytowane znaki zawsze znajdują się w tym samym tokenie.<LF>
zawsze wyłącza flagę cytatu. Inne zachowania różnią się w zależności od kontekstu, ale cytaty nigdy nie zmieniają zachowania<LF>
.<LF>
<LF>
jest pozbawiony<LF>
, to jest traktowany jako literał, co oznacza, że ten proces nie jest rekurencyjny.<LF>
nie w nawiasach<LF>
jest usuwany i analizowanie bieżącej linii jest przerywane.<LF>
w bloku FOR IN w nawiasach<LF>
jest konwertowany na<space>
<LF>
w bloku poleceń w nawiasach<LF>
jest konwertowany na<LF><space>
, a<space>
jest traktowany jako część następnego wiersza bloku poleceń.&
|
<
lub>
, podziel linię w tym miejscu, aby obsłużyć potoki, konkatenację poleceń i przekierowanie.|
) każda strona jest oddzielnym poleceniem (lub blokiem poleceń), które otrzymuje specjalną obsługę w fazie 5.3&
,&&
lub||
polecenia konkatenacji z każdej strony łączenie jest traktowany jako osobna polecenia.<
,<<
,>
lub>>
przekierowania klauzula przekierowania jest analizowany czasowo usunięty, a następnie dodawana na końcu zadanego prądu. Klauzula przekierowania składa się z opcjonalnej cyfry uchwytu pliku, operatora przekierowania i tokenu miejsca docelowego przekierowania.@
, to@
ma specjalne znaczenie. (@
nie jest wyjątkowy w żadnym innym kontekście)@
została usunięta.@
jest przed otwarciem(
, cały blok umieszczony w nawiasach jest wykluczony z echa fazy 3.(
to nie jest specjalny.(
, uruchom nową instrukcję złożoną i zwiększ licznik nawiasów)
kończy instrukcję złożoną i zmniejsza licznik nawiasów.)
działa podobnie do aREM
instrukcji, o ile bezpośrednio następuje po niej ogranicznik tokenu, znak specjalny, nowa linia lub koniec pliku^
(możliwe jest łączenie wierszy)@
usunięciu elementu specjalnego i przeniesieniu przekierowania na koniec).(
działa jako ogranicznik tokenu polecenia, oprócz standardowych ograniczników tokenu<LF>
jako<space>
. Po przeanalizowaniu klauzuli IN wszystkie tokeny są łączone w celu utworzenia pojedynczego tokenu.^
który kończy wiersz, token argumentu jest odrzucany, a kolejny wiersz jest analizowany i dołączany do REM. Powtarza się, dopóki nie będzie więcej niż jeden żeton lub nie będzie ostatniego znaku^
.:
i jest to pierwsza runda fazy 2 (nie jest to restart z powodu CALL w fazie 6), to)
,<
,>
,&
i|
nie ma specjalnego znaczenia. Cała pozostała część wiersza jest traktowana jako część etykiety „polecenie”.^
Nadal jest wyjątkowy, co oznacza, że linia kontynuacja może być używany do dołączania późniejszą linię do etykiety.(
nie ma już specjalnego znaczenia dla pierwszego polecenia, które następuje po niewykonanej etykiecie .|
rura lub&
,&&
czy||
polecenie konkatenacji na linii.Faza 3) Powtórz przeanalizowane polecenie (polecenia) Tylko wtedy, gdy blok poleceń nie rozpoczął się
@
, a funkcja ECHO była WŁĄCZONA na początku poprzedniego kroku.Faza 4)
%X
Rozszerzenie zmiennej FOR : Tylko wtedy, gdy polecenie FOR jest aktywne i polecenia po DO są przetwarzane.%%X
na%X
. W wierszu poleceń obowiązują różne reguły rozszerzania procentowego dla fazy 1. Jest to powód, dla którego w wierszach poleceń używane są zmienne FOR,%X
ale pliki wsadowe%%X
.~modifiers
nie.~modifiers
mają pierwszeństwo przed nazwami zmiennych. Jeśli następujący po nim znak~
jest zarówno modyfikatorem, jak i prawidłową nazwą zmiennej FOR, a istnieje kolejny znak, który jest aktywną nazwą zmiennej FOR, to znak jest interpretowany jako modyfikator.---- Od tego momentu każde polecenie zidentyfikowane w fazie 2 jest przetwarzane oddzielnie.
---- Fazy od 5 do 7 są zakończone dla jednej komendy przed przejściem do następnej.
Faza 5) Opóźnione rozwinięcie: Tylko jeśli opóźnione rozwijanie jest włączone, polecenie nie znajduje się w bloku w nawiasach po żadnej stronie potoku , a polecenie nie jest „nagim” skryptem wsadowym (nazwa skryptu bez nawiasów, CALL, konkatenacja poleceń, lub rura).
!
. Jeśli nie, to token nie jest analizowany - ważne dla^
postaci. Jeśli token zawiera!
, zeskanuj każdy znak od lewej do prawej:^
), następny znak nie ma specjalnego znaczenia, sam daszek jest usuwany!
są zwinięte w jeden!
!
zostaną usunięte<CR>
lub<LF>
)Faza 5.3) Przetwarzanie potoku : tylko wtedy, gdy polecenia znajdują się po obu stronach potoku
Każda strona potoku jest przetwarzana niezależnie i asynchronicznie.
%comspec% /S /D /c" commandBlock"
, więc blok poleceń otrzymuje ponownie fazę, ale tym razem w trybie wiersza poleceń.<LF>
z poleceniem przed i po są konwertowane na<space>&
. Inni<LF>
są pozbawieni.Faza 5.5) Wykonywanie przekierowania: Każde przekierowanie wykryte w fazie 2 jest teraz wykonywane.
||
jest używane .Faza 6) Przetwarzanie CALL / podwajanie Caret: Tylko jeśli token polecenia to CALL lub jeśli tekst przed pierwszym występującym standardowym ogranicznikiem tokena to CALL. Jeśli CALL jest analizowany z większego tokenu polecenia, to nieużywana część jest dodawana do tokenu argumentów przed kontynuowaniem.
/?
. Jeśli zostanie znaleziony w dowolnym miejscu na żetonach, przerwij fazę 6 i przejdź do fazy 7, gdzie zostanie wydrukowana POMOC dla WEZWANIA.CALL
, aby można było ułożyć wiele połączeń CALL&
lub|
(
@
IF
lubFOR
nie jest rozpoznawane jako polecenie wewnętrzne lub zewnętrzne.:
.:
, toFaza 7 nie jest wykonywana dla skryptów CALLed lub: etykiet.
Faza 7) Wykonaj: Polecenie jest wykonywane
+
/
[
]
<space>
<tab>
,
;
lub=
Jeśli poprzedzający tekst jest poleceniem wewnętrznym, zapamiętaj to polecenie
.
\
lub:
Jeśli poprzedzający tekst nie jest poleceniem wewnętrznym, to goto 7.2 W
przeciwnym razie poprzedzający tekst może być poleceniem wewnętrznym. Zapamiętaj to polecenie.
+
/
[
]
<space>
<tab>
,
;
lub=
Jeśli poprzedzający tekst jest ścieżką do istniejącego pliku, przejdź do 7.2 W przeciwnym razie
wykonaj zapamiętane polecenie wewnętrzne.
/?
zostaną wykryte, wyświetlą pomoc zamiast wykonywać swoją funkcję . Większość rozpoznaje,/?
czy pojawia się gdziekolwiek w argumentach. Ale kilka poleceń, takich jak ECHO i SET, wyświetla pomoc tylko wtedy, gdy pierwszy argument token zaczyna się od/?
.set "name=content" ignored
-> wartość =content
to tekst między pierwszym znakiem równości a ostatnim cudzysłowem jest używany jako treść (z wyłączeniem pierwszego równego i ostatniego cudzysłowu). Tekst po ostatnim cudzysłowie jest ignorowany. Jeśli po znaku równości nie ma cudzysłowu, to reszta wiersza jest używana jako treść.
set name="content" not ignored
-> wartość =,"content" not ignored
cała pozostała część wiersza po równości jest używana jako treść, w tym wszelkie możliwe cudzysłowy.
::
zawsze spowoduje błąd, chyba że SUBST jest używany do zdefiniowania woluminu dla.::
Jeśli SUBST jest używany do zdefiniowania woluminu dla
::
, to wolumin zostanie zmieniony i nie będzie traktowany jako etykieta.,
,;
,=
i+
następnie przerwać polecenie Token na pierwsze wystąpienie<space>
,
;
lub=
i poprzedzić resztę do argumentu tokenu (s).Jeśli nie można znaleźć woluminu, przerwij z błędem.
:
, to goto 7.4Zauważ, że jeśli token etykiety zaczyna się od
::
, to nie zostanie osiągnięty, ponieważ poprzedni krok zostanie przerwany z błędem, chyba że SUBST zostanie użyty do zdefiniowania woluminu dla::
.:
, to goto 7.4Zauważ, że rzadko jest to osiągane, ponieważ poprzedni krok zostanie przerwany z błędem, chyba że token polecenia zaczyna się od
::
, a SUBST jest używany do zdefiniowania woluminu dla::
, a cały token polecenia jest prawidłową ścieżką do polecenia zewnętrznego.:
.Zasady zawarte w 7.2 i 7.3 mogą uniemożliwić etykiecie osiągnięcie tego punktu.
Parser wiersza poleceń:
Działa jak BatchLine-Parser, z wyjątkiem:
Faza 1) Procentowa ekspansja:
%*
,%1
itp. Rozwijanie argumentów%var%
pozostaje niezmieniona.%%
. Jeśli var = content, to%%var%%
rozwija się do%content%
.Faza 3) Powtórz przeanalizowane polecenie (a)
Faza 5) Opóźniona rozbudowa: tylko wtedy, gdy włączona jest opcja Opóźniona rozbudowa
!var!
pozostaje niezmieniona.Faza 7) Wykonaj polecenie
::
Parsowanie wartości całkowitych
Istnieje wiele różnych kontekstów, w których cmd.exe analizuje wartości całkowite z ciągów, a reguły są niespójne:
SET /A
IF
%var:~n,m%
(rozwinięcie zmiennej podciąg)FOR /F "TOKENS=n"
FOR /F "SKIP=n"
FOR /L %%A in (n1 n2 n3)
EXIT [/B] n
Szczegóły dotyczące tych reguł można znaleźć w sekcji Zasady dotyczące sposobu analizowania liczb przez program CMD.EXE
Dla każdego, kto chce ulepszyć reguły parsowania cmd.exe, na forum DosTips znajduje się temat do dyskusji, w którym można zgłaszać problemy i proponować.
Mam nadzieję, że to pomaga
Jan Erik (jeb) - Oryginalny autor i odkrywca faz
Dave Benham (dbenham) - Wiele dodatkowych treści i edycji
źródło
)
Naprawdę funkcję prawie jakREM
komendy, gdy licznik nawias 0. Spróbuj zarówno tych z wiersza polecenia:) Ignore this
iecho OK & ) Ignore this
Podczas wywoływania polecenia z okna poleceń, tokenizacja argumentów wiersza poleceń nie jest wykonywana przez
cmd.exe
(inaczej „powłokę”). Najczęściej tokenizacja jest wykonywana przez środowisko uruchomieniowe C / C ++ nowo utworzonych procesów, ale niekoniecznie tak jest - na przykład, jeśli nowy proces nie został napisany w C / C ++ lub jeśli nowy proces zdecyduje się zignorowaćargv
i przetworzyć surowe polecenie dla siebie (np. z GetCommandLine ()). Na poziomie systemu operacyjnego Windows przekazuje wiersze poleceń pozbawione tokenów jako pojedynczy ciąg do nowych procesów. Jest to przeciwieństwo większości powłok * nix, w których powłoka tokenizuje argumenty w spójny, przewidywalny sposób przed przekazaniem ich do nowo utworzonego procesu. Wszystko to oznacza, że możesz doświadczyć bardzo rozbieżnych zachowań tokenizacji argumentów w różnych programach w systemie Windows, ponieważ poszczególne programy często biorą tokenizację argumentów w swoje ręce.Jeśli to brzmi jak anarchia, to w pewnym sensie tak jest. Jednakże, ponieważ duża liczba programów Windows zrobić wykorzystują Microsoft C / C ++ Runtime
argv
może być ogólnie przydatne do zrozumienia , w jaki sposób MSVCRT tokenizes argumenty. Oto fragment:„Język wsadowy” firmy Microsoft (
.bat
) nie jest wyjątkiem w tym anarchicznym środowisku i opracował własne unikalne reguły tokenizacji i ucieczki. Wygląda również na to, że wiersz poleceń cmd.exe wykonuje pewne wstępne przetwarzanie argumentu wiersza poleceń (głównie w celu podstawienia zmiennych i ucieczki) przed przekazaniem argumentu do nowo wykonywanego procesu. Możesz przeczytać więcej o niskopoziomowych szczegółach języka wsadowego i ucieczce cmd w doskonałych odpowiedziach jeb i dbenham na tej stronie.Zbudujmy proste narzędzie wiersza poleceń w C i zobaczmy, co mówi o twoich przypadkach testowych:
(Uwagi: argv [0] jest zawsze nazwą pliku wykonywalnego i jest pomijane poniżej ze względu na zwięzłość. Testowane w systemie Windows XP SP3. Skompilowane za pomocą programu Visual Studio 2005).
I kilka moich własnych testów:
źródło
[a "b" c]
mogłoby się stać[a "b] [c]
przetwarzanie końcowe .GetCommandLine
. Win32 . Być może TinyPerl ignoruje argv i po prostu tokenizuje surową linię poleceń według własnych reguł.Zasady rozszerzenia procentowego
Oto rozszerzone wyjaśnienie Fazy 1 w odpowiedzi jeba (ważne zarówno dla trybu wsadowego, jak i trybu wiersza poleceń).
Faza 1) Ekspansja procentowa Zaczynając od lewej strony, przeskanuj każdy znak w poszukiwaniu
%
lub<LF>
. Jeśli zostanie znaleziony<LF>
)<LF>
wtedy<LF>
dalszą<CR>
)%
, więc przejdź do 1.1%
) pomijane w trybie wiersza poleceń%
następniewymienić
%%
z pojedynczym%
i kontynuować skanowanie*
i rozszerzenia poleceń są włączone, wówczasZamień
%*
na tekst wszystkich argumentów wiersza poleceń (Zamień na nic, jeśli nie ma żadnych argumentów) i kontynuuj skanowanie.<digit>
wtedywymienić
%<digit>
o wartości argumentu (zastąpić niczym jeśli niezdefiniowany) i kontynuować skanowanie.~
i rozszerzenia poleceń są wtedy włączone<digit>
toZamień na
%~[modifiers]<digit>
zmodyfikowaną wartość argumentu (zamień na nic, jeśli nie jest zdefiniowany lub jeśli określono $ PATH: modyfikator nie jest zdefiniowany) i kontynuuj skanowanie.Uwaga: modyfikatory nie uwzględniają wielkości liter i mogą pojawiać się wiele razy w dowolnej kolejności, z wyjątkiem $ PATH: modyfikator może pojawić się tylko raz i musi być ostatnim modyfikatorem przed
<digit>
spójrz na następny ciąg znaków, łamiąc przed
%
lub koniec bufora i nazwij je VAR (może to być pusta lista)%
następniezamień na
%VAR%
wartość WARIANCJA i kontynuuj skanowanieUsuń
%VAR%
i kontynuuj skanowaniespójrz na następny ciąg znaków, łamiąc przed
%
:
lub koniec bufora i nazwij je VAR (może to być pusta lista). Jeśli WARIANCJA zostanie przerwana przed,:
a kolejny znak zostanie%
dołączony:
jako ostatni znak zmiennej WARIANCJA i przerwij przed%
.%
następnieZamień
%VAR%
wartość WARIANCJA i kontynuuj skanowanieUsuń
%VAR%
i kontynuuj skanowanie:
wtedyUsuń
%VAR:
i kontynuuj skanowanie.~
wtedy[integer][,[integer]]%
toZastąp
%VAR:~[integer][,[integer]]%
podciągiem wartości VAR (co może skutkować pustym ciągiem) i kontynuuj skanowanie.=
lub*=
następniewyszukiwania Nieprawidłowy zmienna i zastąpić składni podnosi błąd krytyczny: Wszystkie analizowane polecenia są przerywane, i przerywa przetwarzania wsadowego gdyby w trybie wsadowym!
[*]search=[replace]%
, gdzie wyszukiwanie może obejmować dowolny zestaw znaków z wyjątkiem=
, a zamiana może obejmować dowolny zestaw znaków z wyjątkiem%
, a następnieZamień
%VAR:[*]search=[replace]%
wartość VAR po wykonaniu wyszukiwania i zamiany (prawdopodobnie skutkując pustym ciągiem) i kontynuuj skanowanieUsuń
%
i kontynuuj skanowanie, zaczynając od następnego znaku po%
%
i kontynuuj skanowanie, zaczynając od następnego znaku po zachowanej interlinii%
Powyższe pomaga wyjaśnić, dlaczego ta partia
Daje następujące wyniki:
Uwaga 1 - Faza 1 następuje przed uznaniem instrukcji REM. Jest to bardzo ważne, ponieważ oznacza, że nawet uwaga może generować błąd krytyczny, jeśli ma nieprawidłową składnię rozwijania argumentów lub nieprawidłowe wyszukiwanie zmiennych i zastępowanie składni!
Uwaga 2 - Kolejna interesująca konsekwencja reguł parsowania%: Zmienne zawierające: w nazwie można zdefiniować, ale nie można ich rozwinąć, chyba że zostaną wyłączone rozszerzenia poleceń. Jest jeden wyjątek - nazwę zmiennej zawierającą pojedynczy dwukropek na końcu można rozwinąć, gdy rozszerzenia poleceń są włączone. Nie można jednak wykonywać podciągów ani operacji wyszukiwania i zamiany na nazwach zmiennych kończących się dwukropkiem. Poniższy plik wsadowy (dzięki uprzejmości jeb) demonstruje takie zachowanie
Uwaga 3 - Interesujący wynik kolejności reguł analizowania, które jeb przedstawia w swoim poście: Podczas wykonywania funkcji znajdź i zamień z opóźnionym rozszerzaniem, znaki specjalne zarówno w terminach znajdź i zamień muszą zostać pominięte lub zacytowane. Ale sytuacja jest inna w przypadku ekspansji procentowej - nie można pominąć terminu znajdującego (chociaż można go cytować). Łańcuch zamiany procentu może, ale nie musi, wymagać zmiany znaczenia lub cudzysłowu, w zależności od intencji.
Zasady opóźnionego rozszerzenia
Oto rozszerzone i dokładniejsze wyjaśnienie fazy 5 w odpowiedzi jeb (ważne zarówno dla trybu wsadowego, jak i trybu wiersza poleceń)
Faza 5) Opóźniona ekspansja
Ta faza jest pomijana, jeśli zachodzi którykolwiek z poniższych warunków:
CALL
, w nawiasach, każdy blok postać poleceń (łączenie&
,&&
lub||
) lub rury|
.Opóźniony proces rozszerzania jest stosowany do tokenów niezależnie. Polecenie może mieć wiele tokenów:
for ... in(TOKEN) do
if defined TOKEN
if exists TOKEN
if errorlevel TOKEN
if cmdextversion TOKEN
if TOKEN comparison TOKEN
, Gdzie porównanie jest jednym z==
,equ
,neq
,lss
,leq
,gtr
, lubgeq
Żadna zmiana nie jest dokonywana w tokenach, które nie zawierają
!
.Dla każdego tokena, który zawiera przynajmniej jeden
!
, przeskanuj każdy znak od lewej do prawej w poszukiwaniu^
lub!
, a jeśli zostanie znaleziony, to!
lub^
dosłowne^
to^
!
, tospójrz na następny ciąg znaków, łamiący przed
!
lub<LF>
, i nazwij je VAR (może to być pusta lista)!
następniezamień na
!VAR!
wartość WARIANCJA i kontynuuj skanowanieUsuń
!VAR!
i kontynuuj skanowanieSpójrz na następny ciąg znaków, łamiąc przed
!
,:
lub<LF>
, i nazywają je VAR (może być pusta lista). Jeśli WARIANCJA zostanie przerwana przed,:
a kolejny znak zostanie!
dołączony:
jako ostatni znak zmiennej WARIANCJA i przerwij przed!
!
następnieZamień
!VAR!
wartość WARIANCJA i kontynuuj skanowanieUsuń
!VAR!
i kontynuuj skanowanie:
wtedyUsuń
!VAR:
i kontynuuj skanowanie~
wtedy[integer][,[integer]]!
to Zastąp!VAR:~[integer][,[integer]]!
podciągiem wartości VAR (może to spowodować pusty ciąg) i kontynuuj skanowanie.[*]search=[replace]!
, gdzie wyszukiwanie może obejmować dowolny zestaw znaków z wyjątkiem=
, a zamiana może obejmować dowolny zestaw znaków z wyjątkiem!
, a następnieZamień na
!VAR:[*]search=[replace]!
wartość VAR po wykonaniu wyszukiwania i zamiany (prawdopodobnie skutkuje pustym ciągiem) i kontynuuj skanowanie!
zachowaj wiodący
!
!
źródło
%definedVar:a=b%
vs%undefinedVar:a=b%
i%var:~0x17,-010%
formularzy%<digit>
,%*
lub%~
. A zachowanie zmienia się dla niezdefiniowanych zmiennych. Być może musisz otworzyć drugą odpowiedźJak już wspomniano, do poleceń przekazywany jest cały ciąg argumentów w μSoft land i do nich należy przeanalizowanie go na oddzielne argumenty do własnego użytku. Nie ma w tym spójności między różnymi programami, dlatego nie ma jednego zestawu reguł opisujących ten proces. Naprawdę musisz sprawdzić każdy przypadek narożny pod kątem jakiejkolwiek biblioteki C, której używa twój program.
Jeśli chodzi o
.bat
pliki systemowe , oto ten test:Teraz możemy przeprowadzić kilka testów. Sprawdź, czy możesz dowiedzieć się, co próbuje zrobić μSoft:
Jak dotąd dobrze. (Pominę to, co nieinteresujące
%cmdcmdline%
i%0
od teraz.)Brak rozszerzenia nazwy pliku.
Bez usuwania cudzysłowów, chociaż cudzysłowy zapobiegają dzieleniu argumentów.
Kolejne podwójne cudzysłowy powodują utratę wszelkich specjalnych zdolności analizy, które mogły posiadać. Przykład @ Beniot:
Quiz: Jak przekazać wartość zmiennej środowiskowej jako pojedynczy argument (tj. As
%1
) do pliku bat?Rozsądne analizowanie wydaje się na zawsze zepsute.
Dla rozrywki, spróbuj dodać Różny
^
,\
,'
,&
(& c.) Znaki do tych przykładów.źródło
t
jesta "b c
. Czy masz przepis na uzyskanie tych 6 znaków (a
2 x przestrzeń"
,b
ic
) do stawienia się jako%1
Wewnątrz.cmd
? Podoba mi się jednak twoje myślenie.args "%t:"=""%"
jest całkiem blisko :-)Masz już kilka świetnych odpowiedzi powyżej, ale aby odpowiedzieć na jedną część pytania:
To, co się tam dzieje, polega na tym, że ponieważ masz spację przed znakiem =, tworzona jest zmienna nazywana
%a<space>%
tak, gdyecho %a %
jest ona oceniana poprawnie jakob
.Pozostała część
b% c%
jest następnie oceniana jako zwykły tekst + niezdefiniowana zmienna% c%
, która powinna zostać powtórzona tak, jak wpisana, dla mnieecho %a %b% c%
zwracabb% c%
Podejrzewam, że możliwość wstawiania spacji w nazwach zmiennych jest raczej przeoczeniem niż planowaną „funkcją”
źródło
edit: zobacz zaakceptowaną odpowiedź, co poniżej jest błędne i wyjaśnia tylko, jak przekazać linię poleceń do TinyPerl.
Jeśli chodzi o cytaty, mam wrażenie, że zachowanie jest następujące:
"
zostanie znalezione, zaczyna się globbing łańcucha"
jest jest globbed"
zostanie znalezione:""
(a więc potrójny"
), do ciągu dodawany jest podwójny cudzysłów"
(a więc double"
), to do łańcucha dodawany jest podwójny cudzysłów, a końce globowania łańcucha"
, globbing łańcucha się kończyW skrócie:
"a """ b "" c"""
składa się z dwóch ciągów:a " b "
ic"
"a""
,"a"""
i"a""""
wszystkie są tym samym ciągiem, jeśli znajdują się na końcu wierszaźródło
Zwróć uwagę, że Microsoft opublikował kod źródłowy swojego terminala. Może działać podobnie do wiersza poleceń pod względem analizy składni. Może ktoś jest zainteresowany przetestowaniem odwrotnych reguł analizowania pod kątem zgodności z regułami przetwarzania terminala.
Link do kodu źródłowego.
źródło