Doppelte Anführungszeichen im Stapelskript entkommen


91

Wie würde ich vorgehen, um alle doppelten Anführungszeichen in den Parametern meiner Batchdatei durch maskierte doppelte Anführungszeichen zu ersetzen? Dies ist meine aktuelle Batchdatei, die alle Befehlszeilenparameter innerhalb der Zeichenfolge erweitert:

@echo off
call bash --verbose -c "g++-linux-4.1 %*"

Diese Zeichenfolge wird dann verwendet, um Cygwins Bash aufzurufen und einen Linux-Cross-Compiler auszuführen. Leider werden solche Parameter an meine Batch-Datei übergeben:

"launch-linux-g++.bat" -ftemplate-depth-128 -O3 -finline-functions 
-Wno-inline -Wall  -DNDEBUG   -c 
-o "C:\Users\Me\Documents\Testing\SparseLib\bin\Win32\LinuxRelease\hello.o" 
"c:\Users\Me\Documents\Testing\SparseLib\SparseLib\hello.cpp"

Wenn das erste Anführungszeichen um den ersten übergebenen Pfad das vorzeitige Übergeben des an GCC übergebenen Strings vorzeitig beendet und den Rest der Parameter direkt an bash übergibt (was spektakulär fehlschlägt).

Ich stelle mir vor, wenn ich die Parameter zu einer einzigen Zeichenfolge verketten kann und dann den Anführungszeichen entkomme, sollte es gut funktionieren, aber ich habe Schwierigkeiten zu bestimmen, wie das geht. Weiß jemand?

Antworten:


103

Das Escapezeichen in Batch-Skripten ist ^. Verdoppeln Sie für Zeichenfolgen mit doppelten Anführungszeichen die Anführungszeichen:

"string with an embedded "" character"

5
Das Verdoppeln von Anführungszeichen hat bei mir nicht funktioniert, aber es hat wie ein Champion funktioniert.
Davenpcj

25
^ist das Escape-Zeichen nur in nicht zitierten Zeichenfolgen; In Zeichenfolgen in doppelten Anführungszeichen wird es als Literal behandelt. Im Gegensatz zu Unix-Shells (POSIX-ähnlichen Shells) cmd.exebietet NO KEINE standardisierte Shell- Behandlung von doppelten Anführungszeichen in einer Zeichenfolge mit doppelten Anführungszeichen. Die Interpretation bleibt dem aufgerufenen Programm überlassen (siehe nächster Kommentar).
mklement0

9
(Fortsetzung des vorherigen Kommentars) In der Praxis wenden die meisten ausführbaren Dateien / Skriptinterpreter die C-Konvention an, "Zeichen zu erwarten . als \"innerhalb einer Zeichenfolge in doppelten Anführungszeichen maskiert werden (gilt mindestens für: C / C ++, Python, Perl, Ruby). Im Gegensatz dazu ""wird dies nur in wenigen Fällen erkannt : In Parametern, die an Batchdateien übergeben werden, "" wird es als eingebettetes Anführungszeichen erkannt , bleibt aber%<n> auch nach Entfernen der einschließenden Anführungszeichen mit wie im entsprechenden Parameter erhalten %~<n>. Python erkennt gnädigerweise auch"" als Alternative zu \".
mklement0

89

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 :

    • Beispiel: foo.bat "We had 3"" of rain."

    • Folgendes gilt nur für Batchdateien:

      • ""Nur so kann der Befehl interpreter ( cmd.exe) die gesamte Zeichenfolge in doppelten Anführungszeichen als einzelnes Argument behandeln.

      • Leider werden jedoch nicht nur die einschließenden doppelten Anführungszeichen (wie üblich) beibehalten, sondern auch die doppelten Escape-Anführungszeichen. Das Erhalten der beabsichtigten Zeichenfolge ist also ein zweistufiger Prozess. Angenommen, die Zeichenfolge in doppelten Anführungszeichen wird als erstes Argument übergeben %1:

      • set "str=%~1"entfernt die einschließenden doppelten Anführungszeichen; set "str=%str:""="%"konvertiert dann die doppelten doppelten Anführungszeichen in einfache.
        Stellen Sie sicher, dass Sie die zugehörigen doppelten Anführungszeichen um die Zuordnungsteile verwenden, um eine unerwünschte Interpretation der Werte zu vermeiden.

  • \"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 verBefehls. 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.exediese 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.exeselbst 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.exesieht die folgenden Token, die sich aus einer Fehlinterpretation \"als reguläres Anführungszeichen ergeben:

  • "3\"
  • of
  • snow" "
  • sich ausruhen: & ver.

Da der cmd.exeMeinung & 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 verBerichte cmd.exe).
Der Gesamteffekt ist:

  • Erstens foo.exewird nur mit den ersten 3 Token aufgerufen .
  • Dann wird der Befehl verausgefü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.exeoder 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.exeMetazeichen 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 callAnweisung ü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 callist insgesamt fehlerhaft , da ^sie nicht mehr zum Entkommen von Sonderzeichen verwendet werden kann : z. B.call foo.cmd a^&bleise Unterbrechungen (anstatt auch Literala&bzu übergebenfoo.cmd, wie dies ohne der Fall wärecall) -foo.cmdwird 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 & bder 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 aan ü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 callAnweisung.
    • 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. %~1um eingeschlossene doppelte Anführungszeichen aus dem ersten Parameter zu entfernen), und leider gibt es keine direkten Ich weiß, wie ich echoeinen variablen Wert ohne die beiliegenden doppelten Anführungszeichen originalgetreu drucken kann .
      • Neil bietet eine forProblemumgehung 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.exehat 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.exeund 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.exeund 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-Expressionin 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 .


Schöne Beschreibung! Aber ... Literal use of ^ in double-quoted strings can, be problematic when applying ~ ...nicht wirklich. Die Tilde entfernt nur äußere Anführungszeichen, wenn vorhanden. Das Verlieren von Carets ist ein Problem der Handhabung. Normalerweise set "param=%~1"löst a dies.
Jeb

Vielen Dank, @jeb, das Problem ist in der Tat nicht spezifisch für die Verwendung von ~- Ich habe meine Antwort aktualisiert, um mein neues Verständnis widerzuspiegeln - bitte kommentieren Sie, wenn Sie ein Problem entdecken. Haben Sie eine Erklärung für die Verdoppelung ^, die automatisch auftritt, wenn Sie Parameter an eine callAnweisung übergeben?
mklement0

3
Ich kann nur vermuten, dass jemand bei MS es für brillant hielt. Dass die doppelten Carets in der zweiten Analysephase automatisch entfernt werden. Dies war jedoch ein großer Fehler, da es nicht in Anführungszeichen funktioniert und das Entkommen von Sonderzeichen effektiv verhindert. Als call echo cat^^&dogob es mit keiner Menge Carets alleine lösbar wäre
jeb

Danke, @jeb, ich hatte nicht einmal über die nicht zitierte Verwendung von ^with nachgedacht call, die, wie Sie betonen, schwer gebrochen ist. Es scheint, dass in call echo cat^&dog(Single ^, die dem ordnungsgemäß entgeht &) der Zielbefehl ( echo) niemals aufgerufen wird (!) - der gesamte Befehl schlägt leise fehl. Ich habe die Antwort entsprechend aktualisiert.
mklement0

Gute Antwort. Ich würde es jedoch nicht ""als entkommen empfehlen , "sondern immer \"(siehe meine Antwort für eine weniger gefährliche Möglichkeit, es aus cmd heraus zu verwenden). Ich kenne keine offizielle Dokumentation , die definieren , ""wie ein Zitat entkommen, aber zumindest 2 , das erwähnen \": .NET und VS . Obwohl falsch dokumentiert, folgt Win32 API auch diesen Regeln.
TS

23

Google kam schließlich mit der Antwort. Die Syntax für das Ersetzen von Zeichenfolgen im Stapel lautet wie folgt:

set v_myvar=replace me
set v_myvar=%v_myvar:ace=icate%

Was "repliziere mich" erzeugt. Mein Skript sieht jetzt so aus:

@echo off
set v_params=%*
set v_params=%v_params:"=\"%
call bash -c "g++-linux-4.1 %v_params%"

Welches ersetzt alle Instanzen von "mit \", richtig für Bash entkommen.


9

Als Ergänzung zu der hervorragenden Antwort von mklement0 :

Fast alle ausführbaren Dateien akzeptieren \"als Escape ". Eine sichere Verwendung in cmd ist jedoch fast nur mit DELAYEDEXPANSION möglich.
Um ein Literal explizit "an einen Prozess zu senden , weisen Sie \"es einer Umgebungsvariablen zu und verwenden Sie diese Variable, wenn Sie ein Angebot übergeben müssen. Beispiel:

SETLOCAL ENABLEDELAYEDEXPANSION
set q=\"
child "malicious argument!q!&whoami"

Hinweis SETLOCAL ENABLEDELAYEDEXPANSIONscheint nur in Batch-Dateien zu funktionieren. Starten Sie, um DELAYEDEXPANSION in einer interaktiven Sitzung zu erhalten cmd /V:ON.

Wenn Ihre Batchdatei nicht mit DELAYEDEXPANSION funktioniert, können Sie sie vorübergehend aktivieren:

::region without DELAYEDEXPANSION

SETLOCAL ENABLEDELAYEDEXPANSION
::region with DELAYEDEXPANSION
set q=\"
echoarg.exe "ab !q! & echo danger"
ENDLOCAL

::region without DELAYEDEXPANSION

Wenn Sie dynamischen Inhalt von einer Variablen übergeben möchten, die Anführungszeichen enthält, die maskiert sind und durch die ""Sie ""bei der \"Erweiterung ersetzen können :

SETLOCAL ENABLEDELAYEDEXPANSION
foo.exe "danger & bar=region with !dynamic_content:""=\"! & danger"
ENDLOCAL

Dieser Ersatz ist bei der Stilerweiterung nicht sicher %...%!

Im Falle von OP bash -c "g++-linux-4.1 !v_params:"=\"!" ist die sichere Version.


Wenn aus irgendeinem Grund die vorübergehende Aktivierung von DELAYEDEXPANSION nicht möglich ist, lesen Sie weiter:

Die Verwendung \"aus cmd heraus ist ein bisschen sicherer, wenn man sich immer Sonderzeichen entziehen muss, anstatt nur manchmal. (Es ist weniger wahrscheinlich, ein Caret zu vergessen, wenn es konsistent ist ...)

Um dies zu erreichen, wird jedem Anführungszeichen ein caret ( ^") vorangestellt . Anführungszeichen, die den untergeordneten Prozess erreichen sollen, da Literale zusätzlich mit einem Backlash ( \^") maskiert werden müssen . ALLE Shell-Metazeichen müssen ebenfalls maskiert werden ^, z. B. &=> ^&; |=> ^|; >=>^> ; etc.

Beispiel:

child ^"malicious argument\^"^&whoami^"

Quelle: Jeder zitiert Befehlszeilenargumente falsch , siehe "Eine bessere Methode zum Zitieren".


Um dynamischen Inhalt zu übergeben, muss Folgendes sichergestellt werden:
Der Teil des Befehls, der die Variable enthält, muss als "in Anführungszeichen" betrachtet werden cmd.exe(Dies ist unmöglich, wenn die Variable Anführungszeichen enthalten kann - nicht schreiben%var:""=\"% ). Um dies zu erreichen, werden die letzten "vor der Variablen und die ersten "nach der Variablen nicht ^entkommen. cmd-Metazeichen zwischen diesen beiden "dürfen nicht maskiert werden. Beispiel:

foo.exe ^"danger ^& bar=\"region with %dynamic_content% & danger\"^"

Dies ist nicht sicher, wenn %dynamic_content%nicht übereinstimmende Anführungszeichen enthalten können.


Verstanden, danke. Ja, das kategorische ^Entweichen aller Metazeichen funktioniert robust und kann methodischer angewendet werden (dennoch ist es offensichtlich ein königlicher Schmerz im Körperteil Ihrer Wahl). Ich habe meine Antwort entsprechend aktualisiert (und Ihnen eine Gutschrift gegeben).
mklement0

@ mklement0 Danke! Ja, es ist wirklich ein Schmerz. Es ist nervig und es ist immer noch zu leicht, einen Metazeichen zu vergessen (daher benutze ich meistens den !q!Weg). Hinweis: Ihre Antwort ist etwas inkonsistent , nachdem die letzte Änderung: In der Nähe der Spitze Sie sagen: „Sie nicht verwenden ^"“. Später verwenden Sie ^"als Teil der Problemumgehung. Vielleicht könnten Sie beide Möglichkeiten erklären? (1) Escaping aller Metazeichen (methodischer) / (2) Selektives Escapezeichen von Metazeichen in "nicht foo.exe ^"danger ^& bar=\"%dynamic_content%\"^"zitierten " Regionen (manchmal erforderlich, um dynamischen Inhalt zu übergeben, z. B. - auf diese Weise wird die Variable für cmd angegeben)
TS

Guter Punkt, danke - Antwort aktualisiert. Ich habe auch klarer gemacht, dass der MS-Compiler sowohl \"als auch akzeptiert "". Ich habe auf Ihre Antwort für den komplexeren Ansatz verwiesen. Lassen Sie mich wissen, ob es jetzt Sinn macht.
mklement0

1
@ mklement0 Deine Antwort hat immer Sinn gemacht :-) Ich wollte nur ein paar Ideen für mögliche Verbesserungen geben. Ich habe auch das Beispiel ungefähr %dynamic_content%in meine Antwort aufgenommen. Denken Sie, dass es detailliert genug ist oder muss ich mehr erklären?
TS

3
Cool, danke, dass du mich informiert hast. Gute Idee, das zu lokalisieren setlocal delayedexpansion, aber Sie sollten den Block mit endlocal(kein Argument) beenden . Ehrlich gesagt, mein Kopf begann sich zu drehen und sah deinen Kern an. Wir haben es hier wirklich mit Randfällen zu tun, und ich denke, zukünftige Leser werden zwischen unseren beiden Antworten alles finden, was sie brauchen.
mklement0

-3

Zum Beispiel für das Unreal Engine Automation-Tool, das aus einer Batch-Datei ausgeführt wird - das hat bei mir funktioniert

Beispiel: -cmdline = "-Messaging" -device = device -addcmdline = "- SessionId = session -SessionOwner = 'owner' -SessionName = 'Build' -dataProviderMode = local -LogCmds = 'LogCommodity OFF' -execcmds = 'Automationsliste ; Runtests testen + getrennt + durch + T1 + T2; beenden '"-run

Hoffe das hilft jemandem, der für mich gearbeitet hat.


Versuchen Sie, das Konzept, das Sie gelernt haben, zu destillieren, indem Sie versuchen, ein klares Beispiel zu geben, anstatt eine lange, meist nicht relevante Kopie Ihrer Arbeit einzufügen.
run_the_race
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.