Warum kann die Parametererweiterung "% ~ fI" auf nicht vorhandene Laufwerke "zugreifen"?

8

Ich verwende die folgenden Befehle:

%Vor%

und die Ausgabe:

  

= & amp;: = & amp;: \

     

= & gt;: = & gt;: \

     

= A: = A: \

     

= B: = B: \

     

= C: = C: \

     

....

Da die Variablen =Drive: den zuletzt aufgerufenen Pfad des entsprechenden Laufwerks speichern, sieht es so aus, als ob die Erweiterung %~fI irgendwie auf nicht existierendes Laufwerk zugegriffen hat (was nicht möglich ist). (Alle Parametererweiterungen erzeugen solche Variablen)

    
npocmaka 21.12.2016, 15:55
quelle

4 Antworten

3

Wenn ein Modifizierer im ersetzbaren Parameter for verwendet wird, um ein Pfadelement anzufordern, verwendet der Befehl for (nun, eine Funktion, die den Inhalt der gelesenen Variablen abruft) das GetFullPathName Funktion, um die Eingabe-Zeichenfolge an etwas anzupassen, das bearbeitet werden kann . Diese API-Funktion (na ja, einige der von dieser API aufgerufenen OS-Basisfunktionen) erzeugt das angegebene Verhalten, wenn ein relativer Pfad angefordert wird. Sie können diesen c-Code testen (tut mir leid, nur einen schnellen Code-Test), die ausführbare Datei mit dem ex aufrufen. ;: als erstes Argument.

%Vor%

um etwas wie

zu erhalten %Vor%

EDITED 2016/12/23

Dies ist für Windows 10, aber da sich Windows 7 genauso verhält, sollte es denselben oder ähnlichen Code teilen.

Die Ausgabe von Umgebungszeichenfolgen an die Konsole wird von DisplayEnvVariable function gehandhabt. In älteren Windows-Versionen (checked und XP hat es so gemacht) ruft diese Funktion GetEnvironmentStrings auf, um die Werte abzurufen, aber jetzt (markiert und in Vista wurde geändert) wird ein Zeiger auf einen Speicherbereich verwendet. Irgendwie (in diesem Moment kann ich diesem Problem nicht mehr Zeit geben), zeigt es auf eine nicht aktualisierte Kopie der Umgebung (in diesem Fall wurde die aktualisierte nicht von cmd -Befehl generiert, sondern von einer Basis Rtl -Funktion wird beim Auflösen des aktuellen Laufwerkspfads aufgerufen und erzeugt das beobachtete Verhalten.

Es ist nicht notwendig, den Befehl pushd oder cd auszuführen. Jede Änderung an der Umgebung oder jede Prozesserstellung führt zu einer Aktualisierung des Zeigers.

%Vor%

Sie können die more -Zeile durch eine einfache set "thisIsNotSet=" ersetzen, um das gleiche Ergebnis zu erhalten

    
MC ND 22.12.2016, 13:31
quelle
2

Ich denke, es gibt zwei Dinge, die dazu beitragen:

  1. Ein Laufwerksbuchstabe kann eigentlich jedes andere Zeichen als Leerzeichen sein, / und \ . Sehen Sie sich den Befehl subst an, der beispielsweise auch & akzeptiert (obwohl er nicht in subst aufgeführt ist):

    %Vor%
  2. for greift nur dann auf das Dateisystem zu, wenn es wirklich erforderlich ist. Dies ist der Fall, wenn:

    • Wildcards (wie ? , * ) werden in der Menge verwendet (auf die das Dateisystem per Befehl for sofort zugreifen muss);
    • Die Erweiterung for referenz ( %I ) benötigt Informationen aus dem Dateisystem:

      • für die Modifikatoren ~s , ~a , ~t , ~z und ~$ENV: sind natürlich Informationen aus dem Dateisystem erforderlich;
      • für die Modifizierer ~n , ~x und ~p , und auch die entsprechenden Teile von ~f , was nichts anderes als ~dpnx ist, wird auf das Dateisystem zugegriffen, um den Fall beizubehalten (wenn der Pfad dies nicht tut) existieren, der ursprüngliche Fall wird beibehalten);
      • für die Modifikatoren ~n , ~x , ~p und ~d sowie ~f muss auf das Dateisystem zugegriffen werden, falls ein relativer Pfad angegeben wird, mit oder ohne Angabe eines dedizierten Laufwerks (zum Beispiel, abc\def , D:data , P: ), weil der aktuelle Arbeitsverzeichnispfad (des gegebenen Laufwerks im Fall) bestimmt werden muss;


    Der Modifizierer ~d und auch der entsprechende Teil von ~f wird durch reine String-Manipulation behandelt, solange das Dateisystem nicht gemäß den oben genannten Bedingungen aufgerufen wird.

    Versuchen Sie einfach Ihren ursprünglichen Code, aber mit absoluten Pfaden, wie for %I in (a:\ b:\ c:\ ">:\" "&:\") do @rem %~fI , usw., und Sie werden feststellen, dass es keine entsprechenden =Drive: Variablen gibt.

Zusammenfassung

Laufwerksbuchstaben können buchstäblich fast alle Zeichen sein (siehe subst ). Sobald for auf das Dateisystem zugreift, um nach Laufwerken und Pfaden zu suchen, werden die Laufwerke, auf die zugegriffen wird, in den Variablen =Drive: aufgezeichnet.

    
aschipfl 21.12.2016 20:29
quelle
2

Der Windows-Befehlsinterpreter versucht, den tatsächlichen Namen einer Datei oder eines Verzeichnisses auf Speichermedien mit einer Erweiterung wie %~fI zu erhalten, indem er ein QueryDirectory verarbeitet, wie es bei der Verwendung von Sysinternals Process Monitor angezeigt wird. Aber die Loop-Variable I enthält nur einen String-Wert wie in set definiert.

Aus Sicht des Programmierers, was sollte der Befehlsinterpreter zum Beispiel für den folgenden Code tun?

%Vor%

Es gibt höchstwahrscheinlich keine Datei mit dem Namen #abcdefghi.tmp im Verzeichnis für temporäre Dateien für Systemprozesse. Aber die Ausgabe ist trotzdem

%Vor%

Der Windows-Befehlsinterpreter muss eine Zeichenfolge erstellen, da der Stapelcode eine Zeichenfolge erwartet. Es kann %%~fI nicht durch nichts oder einen Fehlermeldungstext ersetzen, da dies bei der weiteren Verarbeitung der Befehlszeilen in der Batch-Datei zu einem undefinierten Verhalten führen würde.

Das vollständige Beenden der Stapelverarbeitung ist auch keine Option für den Windows-Befehlsinterpreter, da die FOR -Schleife verwendet werden kann, um das Vorhandensein von Dateien zu überprüfen.

Der Windows-Befehlsinterpreter versucht also, aus dem aktuellen Verzeichnis und der aktuellen Variablen-Zeichenkette einen gültigen Dateinamen mit Pfad oder einfach Dateipfad oder einfach Dateinamen zu erstellen, unabhängig vom Vorhandensein der Datei / des Verzeichnisses oder Gültigkeit der erstellten Zeichenfolge.

Der Befehlszeilenbenutzer bzw. Schreiber des Stapelcodes muss beim Erweitern der Schleifenvariablenreferenz nach Gültigkeit oder Existenz und nicht nach dem Windows-Befehlsinterpreter suchen.

    
Mofi 21.12.2016 18:30
quelle
1

IMO die Laufwerke sind nicht wirklich zugegriffen, aber in einem frühen Stadium analysiert Eine einfache for-Schleife kann verwendet werden, um nicht vorhandene Laufwerke \ pathes \ files

zu analysieren %Vor%

Der allerletzte ist ziemlich interessant

    
LotPings 21.12.2016 18:04
quelle

Tags und Links