2012-06-08 10 views
8

Odpowiadając this pytanie znalazłem jakieś dziwne zachowanie, dla których nie mam wyjaśnienieecho jest dodanie przestrzeni gdy używana z rurą

for /f "delims=" %a in ('(for /l %z in (1,1,10^) do @echo %z^)') do @echo %a0 

Zobaczysz numery 10..100, teraz wystarczy dodać rurę, na przykład do sort lub more, cokolwiek: Dodano

for /f "delims=" %a in ('(for /l %z in (1,1,10^) do @echo %z^)^|sort') do @echo %a0 

Będzie przestrzenie między %a i 0! Wygląda jak echo-ing coś przez rurę dodaje spacją, to łatwo zauważyć:

>_tempfile echo no space here 
>_tempfile echo and here's a space|more 

i nawet

>_tempfile <nul set /p =also a space|sort 

(prawdopodobnie używa echo wydrukować znak zachęty)

Nie dzieje się tak, gdy nie ma przekierowania wyjścia (czy do pliku, czy do polecenia). Czy to błąd, czy też czegoś brakuje? Jak pozbyć się przestrzeni? (Oprócz brudnej sposób z oddzielania ostatniego znaku z var:~0,-1)

Odpowiedz

7

Doskonała i interesujące pytanie (+1)

przestrzeń jest wprowadzany przez mechanizm rury parsera CMD, a nie przez sortowanie.

Po uruchomieniu polecenia za pomocą FOR/F polecenie jest wykonywane we własnej powłoce CMD. Ponadto każda strona rury jest wykonywana we własnej powłoce CMD. Aby uzyskać więcej informacji, patrz Why does delayed expansion fail when inside a piped block of code?.

Twoja komenda faktycznie tworzy 3 powłoki CMD, jedną dla polecenia FOR/F, która z kolei tworzy po 2 dla każdej strony rury.

Możesz zobaczyć, jak polecenia są analizowane i podawane do powłoki CMD przy użyciu zmiennej dynamicznej% CMDCMDLINE%. Ponieważ wykonujemy polecenie z wiersza poleceń, musimy dwukrotnie wymazać co najmniej jeden znak w nazwie zmiennej, aby nie był rozwijany, dopóki nie dotrze do najbardziej wewnętrznej powłoki CMD.

Oto komenda z wynikami (wiodący > jest mój wiersz poleceń):

>for /f "delims=" %a in ('(echo %^^^cmdcmdline%^&for /l %z in (1,1,10^) do @echo %z^)^|sort') do @echo %a0 
1 0 
10 0 
2 0 
3 0 
4 0 
5 0 
6 0 
7 0 
8 0 
9 0 
C:\Windows\system32\cmd.exe /S /D /c" (echo %cmdcmdline% & FOR /L %z in (1 1 10) do @ echo %z)" 0 

Ostatni wiersz wyjścia jest linia poleceń używany do lewej strony rury. Możesz zobaczyć, w jaki sposób parser dodał spacje w wielu miejscach.

Można ominąć problem za pomocą prostego skryptu wsadowego, aby wywołać echo wartości zamiast polecenia ECHO.

echoArgs.bat

@echo(%* 

Teraz po uruchomieniu tej komendy można uzyskać Inną metodą pożądanego rezultatu

>for /f "delims=" %a in ('(for /l %z in (1,1,10^) do @echoArgs %z^)^|sort') do @echo %a0 
10 
100 
20 
30 
40 
50 
60 
70 
80 
90 

celu obejścia tego problemu jest utworzenie zmiennej z polecenia ECHO i uciec odpowiednio przed ekspansją zmiennej.

>set [email protected](echo %z) 

>for /f "delims=" %a in ('(for /l %z in (1,1,10^) do %^^^cmd%^)^|sort') do @echo %a0 
10 
100 
20 
30 
40 
50 
60 
70 
80 
90 

EDIT

Przykład >_tempfile echo and here's a space|more jest interesujące. Na końcu pliku wyjściowego znajduje się dodatkowe miejsce. Ale Chad Nouis ma rację, że nic nie jest sortowane z powodu przekierowania lewej strony. Każde polecenie może być użyte po prawej stronie, a wynik będzie taki sam.

Źródłem problemu jest nadal parser, ale sposób, w jaki parser restrukturyzuje komunikat, jest interesujący.

>>_tempfile echo %^cmdcmdline%|rem 

>type _tempfile 
C:\Windows\system32\cmd.exe /S /D /c" echo %cmdcmdline% 1>_tempfile" 

Wskazówki jak przekierowanie jest przesuwany od początku do końca polecenia, a uchwyt pliku 1 wyraźnie dodał. Z pewnością możesz zobaczyć, skąd pochodzi dodatkowa przestrzeń.

+0

Ach, to, co zwiększa wiedzę, zwiększa ból. Nigdy nie myślałem o potoku jako o więcej niż połączenie stdin/stdout. Zaakceptowano odpowiedź na wyjaśnienia, ale nie na rozwiązanie. Oto prosty: 'dla/f" delims = "% a w (" cmd/c "dla/l% z w (1,1,10) do @echo% z"^| sort ") do @echo% a0' –

+0

@ panda-34 - To z pewnością jest inne rozwiązanie. – dbenham

+0

+1, Spóźniłem się, lubię tego typu pytania, ale odpowiedziałeś już na to z dobrą analizą – jeb

0

Operatory przekierowania stosują się do polecenia, do którego są najbliżej - nie do całej linii.

W trzech testowych przypadkach przekierowujesz standardowe wyjście komend echo i set do pliku. Przekierowując standardowe wyjście, nie pozostawia się nic do wysłania do more lub sort.

W przykładzie zagnieżdżonych pętli for, myślę, że istnieją pewne niepotrzebne nawiasy powodujące bóle głowy. Spróbuj zamiast tego:

for /f "delims=" %a in ('for /l %z in (1,1,10^) do @echo %z^|sort') do @echo %a0 
+0

Ale jeśli spojrzysz na zawartość pliku _temp, kiedy został utworzony po lewej stronie rury zobaczysz dodatkowe miejsce na końcu. Jak wyjaśniłem w [moja odpowiedź] (http://stackoverflow.com/a/10950927/1012053), analizator rur wprowadza przestrzeń. Ale masz ważny punkt, że zawartość pliku tymczasowego nie przechodzi przez SORTOWANIE. Twoje rozwiązanie dla sprawy FOR działa. Ale może się zdarzyć, że lewy bok rury jest blokiem poleceń, które muszą znajdować się w parenach. – dbenham

+2

Czy próbowałeś wykonać swoje polecenie? Czy wyniki są uporządkowane według ciebie? –

+0

Widzę, co robi panda-34. Pareny są wymagane, aby całe wyjście FOR było sortowane jako jeden zestaw. Bez parens sortowanie jest stosowane do każdej linii osobno, co oczywiście nie przydaje się. * (jest to skorygowana wersja mojego wcześniej skasowanego komentarza) * – dbenham

Powiązane problemy