Die eigene Antwort von eplawless löst sein spezifisches Problem einfach und effektiv: Sie ersetzt alle "
Instanzen in der gesamten Argumentliste durch \"
. So erfordert Bash doppelte Anführungszeichen in einer Zeichenfolge mit doppelten Anführungszeichen, um dargestellt zu werden.
Um die Frage zu beantworten, wie doppelte Anführungszeichen in einer Zeichenfolge in doppelten Anführungszeichen mitcmd.exe
dem Windows-Befehlszeileninterpreter (ob in der Befehlszeile - oft immer noch fälschlicherweise als "DOS-Eingabeaufforderung" bezeichnet - oder in einer Batchdatei) vermieden werden können: Unten finden Sie einen Blick auf PowerShell .
tl; dr :
Sie müssen verwenden,""
wenn Sie eine Zeichenfolge an eine (andere) Batchdatei übergeben, und Sie können sie ""
mit Anwendungen verwenden, die mit den C / C ++ /. NET-Compilern von Microsoft erstellt wurden (die auch akzeptieren \"
), die unter Windows Python und Node.js enthalten :
\"
ist erforderlich - als einzige Option - von vielen anderen Programmen , (! zB, Ruby, Perl und sogar eigene Windows Powershell von Microsoft ()), aber ihre Nutzung ist NICHT SICHER :
\"
Dies ist das, was viele ausführbare Dateien und Interpreter entweder benötigen - einschließlich Windows PowerShell -, wenn Zeichenfolgen von außen übergeben werden - oder bei Microsoft-Compilern Unterstützung als Alternative zu ""
- letztendlich ist es jedoch Sache des Zielprogramms, die Argumentliste zu analysieren .
- Beispiel:
foo.exe "We had 3\" of rain."
- Die Verwendung von kann jedoch zu
\"
unerwünschter, willkürlicher Ausführung von Befehlen und / oder Eingangs- / Ausgangsumleitungen führen :
- Die folgenden Zeichen stellen dieses Risiko dar:
& | < >
- Das Folgende führt beispielsweise zu einer unbeabsichtigten Ausführung des
ver
Befehls. Weitere Erläuterungen und den nächsten Punkt für eine Problemumgehung finden Sie weiter unten:
foo.exe "3\" of snow" "& ver."
- Für Windows Powershell ,
\""
und "^""
sind robust, aber begrenzte Alternativen (siehe Abschnitt „Aufruf Powershell CLI ...“ weiter unten).
Wenn Sie verwenden müssen \"
, gibt es nur 3 sichere Ansätze , die jedoch recht umständlich sind : Tipp des Hutes an TS für seine Hilfe.
Mithilfe der (möglicherweise selektiven ) verzögerten Variablenerweiterung in Ihrer Batchdatei können Sie Literale \"
in einer Variablen speichern und diese Variable "..."
mithilfe der !var!
Syntax in einer Zeichenfolge referenzieren - siehe die hilfreiche Antwort von TS .
- Der obige Ansatz hat, obwohl er umständlich ist, den Vorteil, dass Sie ihn methodisch anwenden können und dass er bei jeder Eingabe robust funktioniert .
Nur mit LITERAL-Strings - solchen, an denen KEINE VARIABLEN beteiligt sind - erhalten Sie einen ähnlich methodischen Ansatz: Kategorisch ^
- alle cmd.exe
Metazeichen umgehen : " & | < >
und - wenn Sie auch die Variablenerweiterung unterdrücken möchten - %
:
foo.exe ^"3\^" of snow^" ^"^& ver.^"
Andernfalls müssen Sie Ihre Zeichenfolgecmd.exe
\"
so formulieren , dass Sie erkennen, welche Teile der Zeichenfolge aufgrund einer Fehlinterpretation als schließende Trennzeichen als nicht zitiert gelten:
in wörtlichen Teilen, die Shell-Metazeichen enthalten: ^
-scape sie; Anhand des obigen Beispiels &
muss ^
Folgendes entgangen werden:
foo.exe "3\" of snow" "^& ver."
in Teilen mit %...%
Variablenreferenzen im Stil : Stellen Sie sicher, dass cmd.exe
diese als Teil einer "..."
Zeichenfolge betrachtet werden und dass die Variablenwerte selbst keine eingebetteten, unausgeglichenen Anführungszeichen haben - was nicht einmal immer möglich ist .
Hintergrundinformationen finden Sie weiter.
Hintergrund
Hinweis: Dies basiert auf meinen eigenen Experimenten. Lassen Sie mich wissen, wenn ich falsch liege.
POSIX-ähnliche Shells wie Bash auf Unix-ähnlichen Systemen tokenisieren die Argumentliste (Zeichenfolge), bevor sie Argumente einzeln an das Zielprogramm übergeben: Unter anderem erweitern sie die Argumentliste in einzelne Wörter (Wortaufteilung) und entfernen Anführungszeichen aus dem resultierende Wörter (Zitat entfernen). Das Zielprogramm ist ein geben Array von einzelnen Argumenten , mit syntaktischen Anführungszeichen entfernt .
Im Gegensatz dazu tokenisiert der Windows-Befehlsinterpreter die Argumentliste anscheinend nicht und übergibt einfach die einzelne Zeichenfolge, die alle Argumente enthält - einschließlich Anführungszeichen. - zum Zielprogramm.
Es findet jedoch eine Vorverarbeitung statt, bevor die einzelne Zeichenfolge an das Zielprogramm übergeben wird: ^
Escape-Zeichen. Zeichenfolgen mit doppelten Anführungszeichen werden entfernt (sie entziehen sich dem folgenden Zeichen), und Variablenreferenzen (z. B. %USERNAME%
) werden zuerst interpoliert .
Im Gegensatz zu Unix liegt es daher in der Verantwortung des Zielprogramms, die Argumentzeichenfolge zu analysieren und in einzelne Argumente zu zerlegen, wobei Anführungszeichen entfernt werden. Somit können verschiedene Programme hypothetisch erfordern entweichende Methoden unterscheiden und es gibt keinen einzigen entkommen Mechanismus, der wird garantiert mit allen Programmen zur Arbeit - https://stackoverflow.com/a/4094897/45375 enthält ausgezeichneten Hintergrund auf der Anarchie , die Windows - Befehlszeile Parsing.
In der Praxis, \"
ist sehr häufig, aber nicht sicher , wie oben erwähnt:
Da es cmd.exe
selbst nicht \"
als maskiertes Anführungszeichen erkannt wird , kann es spätere Token in der Befehlszeile als nicht zitiert falsch interpretieren und sie möglicherweise als Befehle und / oder Eingabe- / Ausgabeleitungen interpretieren .
Kurz gesagt: Das Problem tritt auf, wenn eines der folgenden Zeichen einer Öffnung folgt oder unausgeglichen ist\"
:& | < >
; beispielsweise:
foo.exe "3\" of snow" "& ver."
cmd.exe
sieht die folgenden Token, die sich aus einer Fehlinterpretation \"
als reguläres Anführungszeichen ergeben:
"3\"
of
snow" "
- sich ausruhen:
& ver.
Da der cmd.exe
Meinung & ver.
ist , dass dies nicht in Anführungszeichen steht , wird es als &
(Befehlssequenzierungsoperator) interpretiert , gefolgt vom Namen eines auszuführenden Befehls ( ver.
- der .
wird ignoriert; Versionsinformationen der ver
Berichte cmd.exe
).
Der Gesamteffekt ist:
- Erstens
foo.exe
wird nur mit den ersten 3 Token aufgerufen .
- Dann wird der Befehl
ver
ausgeführt.
Selbst in Fällen, in denen der versehentliche Befehl keinen Schaden anrichtet, funktioniert Ihr Gesamtbefehl nicht wie vorgesehen, da nicht alle Argumente an ihn übergeben werden.
Viele Compiler / Interpreter erkennen NUR\"
- z. B. den GNU C / C ++ - Compiler, Python, Perl, Ruby und sogar Microsofts eigene Windows PowerShell, wenn sie von aufgerufen werden cmd.exe
- und außer (mit Einschränkungen) für Windows PowerShell gibt es\""
für sie keine einfache Lösung zu diesem Problem.
Im Wesentlichen müssen Sie im Voraus wissen, welche Teile Ihrer Befehlszeile als nicht zitiert und selektiv falsch interpretiert werden^
zitiert alle Instanzen & | < >
in diesen Abschnitten umgehen .
Im Gegensatz dazu ist die Verwendung von ""
SAFE , wird aber leider nur von Microsoft-Compiler-basierten ausführbaren Dateien und Batch-Dateien (im Fall von Batch-Dateien mit den oben beschriebenen Macken) unterstützt, was PowerShell bemerkenswert ausschließt - siehe nächster Abschnitt.
Aufrufen der CLI von PowerShell von cmd.exe
oder POSIX-ähnlichen Shells:
Hinweis: Informationen zum Umgang mit Zitaten in PowerShell finden Sie im unteren Abschnitt .
Wenn von außen aufgerufen - z. B. von cmd.exe
, ob über die Befehlszeile oder eine Batchdatei:
PowerShell [Core] v6 + erkennt jetzt""
(zusätzlich zu\"
) ordnungsgemäß , was sowohl sicher zu verwenden als auch Leerzeichen bewahrt .
pwsh -c " ""a & c"".length "
bricht nicht und gibt richtig nach 6
Windows PowerShell (die Legacy-Edition, deren letzte Version 5.1 ist) erkennt nur \"
und unter Windows auch """
das robustere \""
/"^""
(obwohlPowerShell intern`
als Escape-Zeichen in Zeichenfolgen in doppelten Anführungszeichen verwendet und auch akzeptiert""
- siehe unterer Abschnitt):
Aufrufen von Windows PowerShell auscmd.exe
/ einer Batchdatei:
""
bricht , weil es grundsätzlich nicht unterstützt wird:
powershell -c " ""ab c"".length "
-> Fehler "Der String fehlt der Terminator"
\"
und """
arbeiten im Prinzip , sind aber nicht sicher :
powershell -c " \"ab c\".length "
funktioniert wie vorgesehen: es gibt aus 5
(beachten Sie die 2 Leerzeichen)
- Aber es ist nicht sicher, weil
cmd.exe
Metazeichen den Befehl brechen, es sei denn, entkommen:
powershell -c " \"a& c\".length "
bricht aufgrund der &
, die als maskiert werden müssten^&
\""
ist sicher , aber normalisieren Sie innere Leerzeichen , was unerwünscht sein kann:
powershell -c " \""a& c\"".length "
Ausgänge 4
(!), da die 2 Leerzeichen auf 1 normiert sind.
"^""
ist speziell für Windows PowerShell die beste Wahl , da es sowohl sicher als auch Whitespace-konservierend ist. Mit PowerShell Core (unter Windows) entspricht es jedoch der\""
Whitespace- Normalisierung . Dank geht an Venryx für die Entdeckung dieses Ansatzes.
powershell -c " "^""a& c"^"".length "
funktioniert : bricht nicht - trotz &
- und gibt aus 5
, dh korrekt erhaltenes Leerzeichen.
PowerShell Core : pwsh -c " "^""a& c"^"".length "
funktioniert , gibt aber aus 4
, dh normalisiert Leerzeichen , wie \""
auch.
Auf Unix-ähnlichen Plattformen (Linux, macOS) beim Aufrufen der CLI von PowerShell [Core]pwsh
über eine POSIX-ähnliche Shell wie bash
:
Sie müssen Folgendes verwenden\"
, das jedoch sowohl sicher als auch weißraumerhaltend ist :
$ pwsh -c " \"a& c|\".length" # OK: 5
Verwandte Informationen
^
kann nur als Escape - Zeichen verwendet werden in nicht notierte Strings - innerhalb von Strings in doppelten Anführungszeichen, ^
ist nicht besonders und als wörtliche behandelt.
- CAVEAT : Die Verwendung von
^
in-Parametern, die an die call
Anweisung übergeben werden, ist fehlerhaft (dies gilt für beide Verwendungen von call
: Aufrufen einer anderen Batchdatei oder Binärdatei und Aufrufen einer Unterroutine in derselben Batchdatei):
^
Fälle , in doppelten Anführungszeichen Werte werden aus unerklärlichen Gründen verdoppelt , übergeben Sie den Wert verändern wird: zum Beispiel , wenn die Variable %v%
enthält Literalwert a^b
, call :foo "%v%"
Abtretungsempfänger "a^^b"
zu (!) %1
(der erste Parameter) in Unterprogramm :foo
.
- Die nicht zitierte Verwendung von
^
with call
ist insgesamt fehlerhaft , da ^
sie nicht mehr zum Entkommen von Sonderzeichen verwendet werden kann : z. B.call foo.cmd a^&b
leise Unterbrechungen (anstatt auch Literala&b
zu übergebenfoo.cmd
, wie dies ohne der Fall wärecall
) -foo.cmd
wird zumindest unter Windows nicht einmal aufgerufen (!) 7.
Austretende eine Literal %
ist ein Sonderfall , leider die erfordert unterschiedliche Syntax je nachdem , ob eine Zeichenkette auf der angegeben ist Kommandozeile vs. in einer Stapeldatei ; Siehe https://stackoverflow.com/a/31420292/45375
- Kurz gesagt: Verwenden Sie in einer Batch-Datei
%%
. %
Kann in der Befehlszeile nicht maskiert werden. Wenn Sie jedoch ein ^
am Anfang, Ende oder innerhalb eines Variablennamens in einer nicht in Anführungszeichen gesetzten Zeichenfolge (z. B. echo %^foo%
) platzieren, können Sie die Erweiterung von Variablen (Interpolation) verhindern. %
Instanzen in der Befehlszeile, die nicht Teil einer Variablenreferenz sind, werden als Literale behandelt (z 100%
. B. ).
Um sicher mit variablen Werten zu arbeiten, die Leerzeichen und Sonderzeichen enthalten können :
- Zuweisung : Fügen Sie sowohl den Variablennamen als auch den Wert in ein einfaches Paar in doppelte Anführungszeichen ein .
set "v=a & b"
Weist z. B. a & b
der Variablen einen Literalwert zu %v%
(im Gegensatz dazu set v="a & b"
würden die doppelten Anführungszeichen Teil des Werts sein). Escape-Literal- %
Instanzen als %%
(funktioniert nur in Batch-Dateien - siehe oben).
- Referenz : Variablenreferenzen in doppelten Anführungszeichen , um sicherzustellen, dass ihr Wert nicht interpoliert wird. z. B.
echo "%v%"
unterwirft den Wert von nicht %v%
Interpolation und Drucken "a & b"
(beachten Sie jedoch, dass die doppelten Anführungszeichen immer auch gedruckt werden). Im Gegensatz dazu wird echo %v%
das Literal a
an übergeben echo
, &
als Befehlssequenzierungsoperator interpretiert und daher versucht, einen Befehl mit dem Namen auszuführen b
.
Beachten Sie auch die oben genannten Einschränkungen bei der Verwendung ^
mit der call
Anweisung.
- Externe Programme kümmern sich normalerweise um das Entfernen von doppelten Anführungszeichen um Parameter, aber wie bereits erwähnt, müssen Sie dies in Batch-Dateien selbst tun (z. B.
%~1
um eingeschlossene doppelte Anführungszeichen aus dem ersten Parameter zu entfernen), und leider gibt es keine direkten Ich weiß, wie ich echo
einen variablen Wert ohne die beiliegenden doppelten Anführungszeichen originalgetreu drucken kann .
- Neil bietet eine
for
Problemumgehung an, die funktioniert , solange der Wert keine doppelten Anführungszeichen enthält . z.B:
set "var=^&')|;,%!"
for /f "delims=" %%v in ("%var%") do echo %%~v
cmd.exe
hat nicht erkennen einzelne -quotes als String - Trennzeichen - sie als Literale behandelt werden und nicht im Allgemeinen zu umgrenzen Strings mit eingebetteten Leerzeichen verwendet werden kann; Daraus folgt auch, dass die an die einfachen Anführungszeichen angrenzenden Token und alle dazwischen liegenden Token als nicht zitiert behandelt cmd.exe
und entsprechend interpretiert werden.
- Da Zielprogramme letztendlich ihre eigene Argumentanalyse durchführen, erkennen einige Programme wie Ruby auch unter Windows Zeichenfolgen in einfachen Anführungszeichen. Im Gegensatz dazu erkennen ausführbare C / C ++ - Dateien, Perl und Python sie nicht .
Selbst wenn dies vom Zielprogramm unterstützt wird, ist es nicht ratsam, Zeichenfolgen in einfachen Anführungszeichen zu verwenden, da deren Inhalt nicht vor potenziell unerwünschter Interpretation durch geschützt ist cmd.exe
.
Zitiert aus innerhalb Powershell:
Windows PowerShell ist eine viel fortschrittlichere Shell als cmd.exe
und seit vielen Jahren ein Teil von Windows (und PowerShell Core brachte die PowerShell-Erfahrung auch auf MacOS und Linux).
PowerShell arbeitet intern konsistent in Bezug auf das Zitieren:
- Verwenden Sie in Zeichenfolgen mit doppelten Anführungszeichen
`"
oder ""
, um doppelte Anführungszeichen zu umgehen
- Verwenden Sie
''
in Zeichenfolgen in einfachen Anführungszeichen, um einfache Anführungszeichen zu umgehen
Dies funktioniert in der PowerShell-Befehlszeile und beim Übergeben von Parametern an PowerShell-Skripts oder -Funktionen in PowerShell.
(Wie oben erläutert, erfordert das Übergeben eines maskierten Anführungszeichens von außen an PowerShell \"
oder, robuster, \""
nichts anderes.)
Leider beim Aufruf externe Programme von Powershell, sind Sie mit der Notwendigkeit, sowohl unterbringen konfrontieren Powershell eigene zitiert Regeln und für das zu entkommen Zielprogramm:
Dieses problematische Verhalten wird auch in dieser Antwort diskutiert und zusammengefasst
Doppelte Anführungszeichen in Zeichenfolgen mit doppelten Anführungszeichen :
Betrachten Sie eine Zeichenfolge "3`" of rain"
, die PowerShell intern in ein Literal übersetzt 3" of rain
.
Wenn Sie diese Zeichenfolge an ein externes Programm übergeben möchten, müssen Sie das Escapezeichen des Zielprogramms zusätzlich zu dem von PowerShell anwenden . Angenommen, Sie möchten die Zeichenfolge an ein C-Programm übergeben, das erwartet, dass eingebettete doppelte Anführungszeichen wie folgt maskiert werden \"
:
foo.exe "3\`" of rain"
Beachten Sie, wie beide `"
- Powershell glücklich zu machen - und das \
- das Zielprogramm glücklich zu machen - vorhanden sein muss.
Die gleiche Logik gilt für das Aufrufen einer Batchdatei, in der ""
Folgendes verwendet werden muss:
foo.bat "3`"`" of rain"
Im Gegensatz dazu erfordert das Einbetten von einfachen Anführungszeichen in eine Zeichenfolge mit doppelten Anführungszeichen überhaupt kein Escapezeichen .
Single -quotes innerhalb einzelner -quoted Saiten Sie nicht benötigen zusätzliche entkommen; Überlegen Sie'2'' of snow'
, was PowerShell 'Darstellung von ist2' of snow
.
foo.exe '2'' of snow'
foo.bat '2'' of snow'
PowerShell übersetzt Zeichenfolgen in einfachen Anführungszeichen in Zeichenfolgen in doppelten Anführungszeichen, bevor sie an das Zielprogramm übergeben werden.
Allerdings Doppel -quotes innerhalb einzelner -quoted Strings , die nicht brauchen , zu entkommen Powershell , müssen nach wie vor für die entronnen sein Zielprogramm :
foo.exe '3\" of rain'
foo.bat '3"" of rain'
Powershell v3 eingeführt , um die magische --%
Option , die genannte Stop-Parsing - Symbol , das einige der Schmerzen lindert, durch nichts vorbei , nachdem er uninterpretiert in das Zielprogramm, speichern für cmd.exe
-Stil umweltVariablenReferenzen (beispielsweise %USERNAME%
), die sich erweitert; z.B:
foo.exe --% "3\" of rain" -u %USERNAME%
Beachten Sie, wie die eingebetteten Umschreibungen "
als \"
nur für das Zielprogramm (und nicht auch für Powershell als \`"
) ausreichend.
Dieser Ansatz:
- lässt keine Escapezeichen zu ,
%
um Erweiterungen von Umgebungsvariablen zu vermeiden.
- schließt die direkte Verwendung von PowerShell-Variablen und -Ausdrücken aus; Stattdessen muss die Befehlszeile in einem ersten Schritt in eine Zeichenfolgenvariable eingebaut und
Invoke-Expression
in einem zweiten mit aufgerufen werden .
Trotz der vielen Fortschritte hat PowerShell das Entkommen beim Aufrufen externer Programme nicht wesentlich erleichtert. Es wurde jedoch die Unterstützung für Zeichenfolgen in einfachen Anführungszeichen eingeführt.
Ich frage mich , ob es in der Windows - Welt zu immer Schalter auf das Unix - Modell zu lassen , die grundsätzlich möglich ist Shell alles tun , die tokenization und Zitat Entfernung vorhersagbar , vorne , und zwar unabhängig von dem Zielprogramm , und rufen Sie dann das Zielprogramm durch die resultierenden Token vorbei .