Unerwartete doppelte Verzeichnisnamen nach dem Erweitern von% dp0 in einer BAT-Datei

867
Vladimir Reshetnikov

Ich bin unter Windows 10 Enterprise x64. Ich habe die folgende Hierarchie von Verzeichnissen mit einer BAT-Datei auf der innersten Ebene:

C:\ dir\ my files\ run.bat 

Die BAT-Datei enthält die folgenden Zeilen:

@pushd %~dp0 @echo %~dp0 @popd 

(Die Bedeutung und Verwendung von %~dp0wird im Hilfethema for /?und in dieser Antwort erläutert. )

Wenn ich die BAT-Datei von einer Eingabeaufforderung mit dem aktuellen Verzeichnis aus ausführen C:\dir\my files, erhalte ich ein sehr vernünftiges Ergebnis:

C:\dir\my files>run.bat C:\dir\my files\ 

Wenn ich es aber vom übergeordneten Verzeichnis aus aufrufe C:\dir, bekomme ich:

C:\dir>"my files"\run.bat C:\dir\my files\my files"\ 

Huh Beachten Sie, dass der innerste Verzeichnisname doppelt vorhanden ist und dass "\am Ende einige Zeichen vorhanden sind . Versuchen wir es mal anders:

C:\dir>"my files\run.bat" C:\dir\my files\my files\ 

Die verirrten Zeichen sind verschwunden, der Verzeichnisname ist jedoch immer noch doppelt vorhanden. Was ist eine Erklärung dafür? Wie kann ich die BAT-Datei so ändern, dass sie unabhängig vom Verzeichnis, in dem sie aufgerufen wurde, dieselbe Ausgabe ergibt?

Natürlich ist mein reales Szenario komplizierter als diese vereinfachte Version. Der Wert von %~dp0wird mit anderen Zeichenfolgen verkettet, den Umgebungsvariablen zugewiesen, als Argument an andere Skripte übergeben usw.

7
Versuchen Sie, die Datei in .cmd umzubenennen und zu sehen, ob sich etwas ändert. Kirill Osenkov vor 6 Jahren 0
@KirillOsenkov Keine Änderungen Vladimir Reshetnikov vor 6 Jahren 0
Ich habe eine vernünftige Problemumgehung gefunden: Verwenden Sie stattdessen die Variable% cd%, nachdem ich das neue aktuelle Verzeichnis abschiebe. Ich verstehe immer noch nicht, warum es vorher nicht funktioniert hat. Vladimir Reshetnikov vor 6 Jahren 0
Versuchen Sie es wie folgt: `. \" Meine Dateien "\ run.bat` Nicke Manarin vor 6 Jahren 0
@NickeManarin Ich kann nicht steuern, wie ein Benutzer die BAT-Datei aufruft. Ich habe nur die Kontrolle über den Inhalt. Vladimir Reshetnikov vor 6 Jahren 2

2 Antworten auf die Frage

4
dbenham

Dies ist ein bekannter Fehler in cmd.exe - %~dp0und Varianten können zu falschen Ergebnissen führen, wenn der Pfad zum Batch-Skript angegeben wurde.

Es gibt eine Problemumgehung. Sie können zuverlässig den Wert aus einem gerufenen Unterprogramm erhalten (beachten Sie, dass mindestens ein Modifikator wie ~d, ~fusw. verwendet werden müssen, was Sie das Unterprogramm erhalten :label)

@echo off setlocal pushd %~dp0 echo From main fails: "%~dp0" call :test popd exit /b  :test echo From subroutine OK: "%~dp0" 

- BEISPIELAUSGABE -

d:\dir>"my files\test.bat" From main fails: "d:\dir\my files\my files\" From subroutine OK: "d:\dir\my files\" 
1
porges

As a workaround, store the directory up-front:

set "dir=%~dp0" 

This is because %0 is really path-as-invoked (like argv arg 0), so in your examples it's either "my files"\run.bat or "my files\run.bat".

When you do %~dp0, cmd.exe is building up the full path relative to the current directory and then extracting the parts you asked for.

After you pushd, the 'full path' (%~f0) is going to be either:

C:\dir\my files\my files\run.bat C:\dir\my files\my files"\run.bat 

... and then trim off the filename to get your results.