9 Stimmen

Echo fügt Leerzeichen hinzu, wenn es mit einem senkrechten Strich verwendet wird

Beim Beantworten dieser Frage habe ich ein seltsames Verhalten festgestellt, für das ich keine Erklärung habe

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

Sie werden Zahlen von 10..100 sehen, fügen Sie jetzt einfach das Pipe-Zeichen hinzu, z.B. zu sort oder more, was auch immer:

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

Es werden Leerzeichen zwischen %a und 0 hinzugefügt! Es scheint, als würde das Echoen von etwas durch ein Pipe-Zeichen ein nachgestelltes Leerzeichen hinzufügen, das man leicht sehen kann:

>_tempfile echo kein Leerzeichen hier
>_tempfile echo und hier ist ein Leerzeichen|more

und sogar

>_tempfile 

``

(verwendet wahrscheinlich echo, um die Eingabeaufforderung anzuzeigen)

Dies passiert nicht, wenn es keine Ausgabeweiterleitung gibt (egal ob in eine Datei oder für Befehl). Ist es ein Bug oder übersehe ich etwas? Wie werde ich das Leerzeichen los? (abgesehen vom schmutzigen Trick, das letzte Zeichen mit var:~0,-1 zu entfernen)

``

8voto

dbenham Punkte 122915

Ausgezeichnete und interessante Frage (+1)

Der Abstand wird durch den Pipe-Mechanismus des CMD-Parsers eingeführt, nicht durch SORT.

Wenn Sie ein Befehl mit FOR /F ausführen, wird der Befehl in seiner eigenen CMD-Shell ausgeführt. Außerdem wird jede Seite einer Pipe in ihrer eigenen CMD-Shell ausgeführt. Siehe Warum schlägt die verzögerte Erweiterung fehl, wenn sie sich innerhalb eines gepipeten Codeblocks befindet? für weitere Informationen.

Ihr Befehl instanziiert also tatsächlich 3 CMD-Shells, einen für den FOR /F-Befehl, der wiederum 2 für jede Seite der Pipe erstellt.

Sie können sehen, wie die Befehle analysiert und in die CMD-Shell mithilfe der dynamischen Variable %CMDCMDLINE% eingegeben werden. Da wir den Befehl von der Befehlszeile ausführen, müssen wir mindestens ein Zeichen im Variablennamen zweimal escapen, damit es nicht expandiert wird, bis es die innerste CMD-Shell erreicht.

Hier ist der Befehl mit den Ergebnissen (das führende > ist meine Eingabeaufforderung):

>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

Die letzte Ausgabezeile ist die Befehlszeile, die für die linke Seite der Pipe verwendet wurde. Sie können sehen, wie der Parser an mehreren Stellen Leerzeichen hinzugefügt hat.

Sie können das Problem umgehen, indem Sie ein einfaches Stapelskript verwenden, um den Wert zu echoen, anstelle des ECHO-Befehls.

echoArgs.bat

@echo(%*

Wenn Sie diesen Befehl jetzt ausführen, erhalten Sie das gewünschte Ergebnis

>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

Eine weitere Methode, um das Problem zu umgehen, besteht darin, eine Variable mit Ihrem ECHO-Befehl zu erstellen und die Expansion der Variable entsprechend zu escapen.

>set cmd=@(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

BEARBEITEN

Das >_tempfile echo and here's a space|more Beispiel ist auch interessant. Am Ende der Ausgabedatei befindet sich ein zusätzliches Leerzeichen. Aber Chad Nouis hat recht, dass nichts sortiert wird, aufgrund der Umleitung auf der linken Seite. Jeder Befehl könnte auf der rechten Seite verwendet werden und das Ergebnis wäre dasselbe.

Die Ursache des Problems ist immer noch der Parser, aber die Art und Weise, wie der Parser den Befehl umstrukturiert, ist interessant.

>>_tempfile echo %^cmdcmdline%|rem

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

Beachten Sie, wie die Umleitung vom Anfang zum Ende des Befehls verschoben wird und der Dateigriff von 1 explizit hinzugefügt wird. Sie können sicherlich sehen, wo das zusätzliche Leerzeichen herkommt.

0voto

Chad Nouis Punkte 6641

Weiterleitungsoperatoren gelten für den Befehl, der ihnen am nächsten liegt - nicht für die gesamte Zeile.

In Ihren drei Testfällen leiten Sie die Standardausgabe der echo- und set-Befehle in eine Datei um. Wenn die Standardausgabe umgeleitet wird, bleibt nichts zum Pfeifen nach more oder sort übrig.

In Ihrem verschachtelten For-Loop-Beispiel denke ich, dass einige unnötige Klammern die Kopfschmerzen verursachen. Versuchen Sie stattdessen dies:

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X