Diese Frage begann die Diskussion über diesen Punkt, und es wurden einige Tests durchgeführt, um herauszufinden, warum. Nach einiger Fehlersuche in cmd.exe
... (dies ist für eine 32 bit Windows XP cmd.exe aber da das Verhalten auf neueren Systemversionen konsistent ist, wird wahrscheinlich der gleiche oder ein ähnlicher Code verwendet)
In der Antwort von Jeb heißt es
It's a problem with the quotes and %~0.
cmd.exe handles %~0 in a special way
und hier hat Jeb recht.
Im aktuellen Kontext der laufenden Batch-Datei gibt es einen Verweis auf die aktuelle Batch-Datei, eine "Variable", die den vollständigen Pfad und Dateinamen der laufenden Batch-Datei enthält.
Wenn auf eine Variable zugegriffen wird, wird ihr Wert aus einer Liste verfügbarer Variablen abgerufen, aber wenn die angeforderte Variable %0
und es wurde ein Modifikator angefordert ( ~
verwendet wird), werden die Daten in der laufenden Chargenreferenz "Variable" verwendet.
Aber die Verwendung von ~
hat eine weitere Auswirkung auf die Variablen. Wenn der Wert in Anführungszeichen steht, werden die Anführungszeichen entfernt. Und hier gibt es einen Fehler im Code. Er ist etwa so kodiert (hier vereinfacht Assembler zu Pseudocode)
value = varList[varName]
if (value && value[0] == quote ){
value = unquote(value)
} else if (varName == '0') {
value = batchFullName
}
Und ja, das bedeutet, dass, wenn die Batch-Datei zitiert wird, der erste Teil der if
ausgeführt und der vollständige Verweis auf die Stapeldatei wird nicht verwendet. Stattdessen wird die Zeichenfolge abgerufen, die beim Aufruf der Stapeldatei als Verweis auf diese verwendet wird.
Was geschieht dann? Wenn beim Aufruf der Batch-Datei der vollständige Pfad verwendet wurde, gibt es kein Problem. Wird jedoch beim Aufruf nicht der vollständige Pfad verwendet, muss jedes Element des Pfades, das im Batch-Aufruf nicht vorhanden ist, abgerufen werden. Bei diesem Abruf wird von relativen Pfaden ausgegangen.
Eine einfache Batch-Datei ( test.cmd
)
@echo off
echo %~f0
Beim Aufruf mit test
(keine Erweiterung, keine Anführungszeichen), erhalten wir c:\somewhere\test.cmd
Beim Aufruf mit "test"
(keine Erweiterung, Anführungszeichen), erhalten wir c:\somewhere\test
Im ersten Fall, ohne Anführungszeichen, wird der korrekte interne Wert verwendet. Im zweiten Fall, da der Aufruf in Anführungszeichen steht, wird die Zeichenkette für den Aufruf der Batch-Datei ( "test"
) ist nicht zitiert und wird verwendet. Da wir einen vollständigen Pfad anfordern, wird er als relativer Verweis auf etwas namens test
.
Das ist der Grund. Wie ist es zu lösen?
Aus dem C#-Code
-
Verwenden Sie keine Anführungszeichen: cmd /c batchfile.cmd
-
Wenn Anführungszeichen erforderlich sind, verwenden Sie den vollständigen Pfad im Aufruf der Batch-Datei. Auf diese Weise %0
enthält alle erforderlichen Informationen.
Aus der Stapeldatei
Die Stapeldatei kann in beliebiger Weise von jedem Ort aus aufgerufen werden. Die einzige zuverlässige Möglichkeit, die Informationen über die aktuelle Batch-Datei abzurufen, ist die Verwendung eines Unterprogramms. Wenn ein Modifikator ( ~
) verwendet wird, wird die %0
verwendet die interne "Variable", um die Daten zu erhalten.
@echo off
setlocal enableextensions disabledelayedexpansion
call :getCurrentBatch batch
echo %batch%
exit /b
:getCurrentBatch variableName
set "%~1=%~f0"
goto :eof
Dies gibt den vollständigen Pfad zur aktuellen Batch-Datei auf der Konsole aus, unabhängig davon, wie Sie die Datei aufrufen, mit oder ohne Anführungszeichen.
Hinweis : Warum funktioniert es? Warum die %~f0
Referenz innerhalb eines Unterprogramms einen anderen Wert zurückgeben? Die Daten, auf die innerhalb der Unterroutine zugegriffen wird, sind nicht dieselben. Wenn die call
ausgeführt wird, wird ein neuer Stapeldateikontext im Speicher erstellt, und die interne "Variable" wird zur Initialisierung dieses Kontexts verwendet.