Domanda

Come potrei sostituire tutte le virgolette doppie nei parametri del mio file batch con virgolette doppie con escape?Questo è il mio file batch corrente, che espande tutti i parametri della riga di comando all'interno della stringa:

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

Quindi utilizza quella stringa per effettuare una chiamata alla bash di Cygwin, eseguendo un cross-compilatore Linux.Sfortunatamente, ricevo parametri come questi passati al mio file batch:

"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"

Dove la prima virgoletta attorno al primo percorso passato termina prematuramente la stringa passata a GCC e passa il resto dei parametri direttamente a bash (che fallisce in modo spettacolare).

Immagino che se riesco a concatenare i parametri in un'unica stringa e poi a sfuggire alle virgolette dovrebbe funzionare bene, ma ho difficoltà a determinare come farlo.Qualcuno sa?

È stato utile?

Soluzione 3

Google alla fine si avvicinò con la risposta. La sintassi per la sostituzione di stringa in batch è questo:

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

Il che produce "me replicare". Il mio script ora assomiglia a questo:

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

che sostituisce tutte le istanze di " con \", adeguatamente sfuggito per bash.

Altri suggerimenti

Il carattere di escape in script batch è ^. Ma per stringhe tra doppi apici, raddoppiare le virgolette:

"string with an embedded "" character"

la risposta di eplawless risolve in modo semplice ed efficace il suo problema specifico:sostituisce tutto " istanze nell'intero elenco di argomenti con \", che è il modo in cui Bash richiede che le virgolette doppie all'interno di una stringa siano rappresentate.

Per rispondere in generale alla domanda di come sfuggire alle virgolette doppie all'interno di una stringa tra virgolette doppie utilizzando cmd.exe, l'interprete della riga di comando di Windows (sia sulla riga di comando - spesso ancora erroneamente chiamata "prompt di DOS" - sia in un file batch):Vedi in basso per uno sguardo PowerShell.

tl; dott:

  • Voi dovere utilizzo "" quando si passa una stringa ad un altro) file batch E tu Maggio utilizzo "" con le applicazioni create con Microsoftcompilatori C/C++/.NET di (Quale Anche accettare \"), che su Windows include Python e Node.js:

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

    • Quanto segue si applica solo ai file batch:

      • "" è l'unico modo per ottenere l'interprete dei comandi (cmd.exe) per trattare l'intera stringa tra virgolette doppie come a separare discussione.

      • Purtroppo, tuttavia, non vengono mantenute solo le virgolette doppie racchiuse (come al solito), ma lo sono anche quelle con escape raddoppiato, quindi ottenere la stringa desiderata è un processo in due fasi;ad esempio, presupponendo che la stringa tra virgolette doppie venga passata come primo argomento, %1:

      • set "str=%~1" rimuove le virgolette doppie racchiuse; set "str=%str:""="%" quindi converte le virgolette doppie raddoppiate in virgolette singole.
        Assicurarsi di utilizzare le virgolette doppie attorno alle parti dell'assegnazione per evitare interpretazioni indesiderate dei valori.

  • \" È necessario - come unica opzione - da molti altri programmi, (ad esempio Ruby, Perl e persino PowerShell di Microsoft (!)), ma IL SUO UTILIZZO NON È SICURO:

    • \" è ciò che molti eseguibili e interpreti neanche richiedere - incluso PowerShell di Microsoft quando vengono passate le stringhe da fuori - o, nel caso di Compilatori di Microsoft, supporto in alternativa a "" - alla fine, però, spetta al programma di destinazione analizzare l'elenco degli argomenti.
      • Esempio: foo.exe "We had 3\" of rain."
    • TUTTAVIA, L'USO DI \" PUÒ RISULTARE IN UN'ESECUZIONE INSIDERATA E ARBITRARIA DI COMANDI e/o REDIREZIONAZIONI DI INPUT/OUTPUT:
      • I seguenti personaggi presentano questo rischio: & | < >
      • Ad esempio, quanto segue comporta l'esecuzione involontaria di ver comando;vedere più avanti per una spiegazione e il punto elenco successivo per una soluzione alternativa:
        • foo.exe "3\" of snow" "& ver."
    • Per PowerShell SU finestre, \"" E "^"" sono alternative robuste, ma limitate (vedere la sezione "Chiamata della CLI di PowerShell..." di seguito).
  • Se devi usare \", ce ne sono solo 3 sicuro approcci, che però sono piuttosto ingombrante: Punta di cappello a T S per il suo aiuto.

    • Utilizzando (possibilmente selettivo) espansione ritardata delle variabili nel tuo file batch, puoi memorizzare letterale \" in un variabile e fare riferimento a quella variabile all'interno di a "..." stringa utilizzando !var! sintassi - Vedere La risposta utile di T S.

      • L'approccio di cui sopra, nonostante sia macchinoso, ha il vantaggio di poterlo applicare metodicamente e che funzioni robustamente, con qualsiasi input.
    • Solo con le stringhe LETTERALI - quelle che NON coinvolgono VARIABILI - ottieni un approccio altrettanto metodico:categoricamente ^-fuga Tutto cmd.exe metacaratteri: " & | < > e - se vuoi anche sopprimere l'espansione variabile - %:
      foo.exe ^"3\^" of snow^" ^"^& ver.^"

    • Altrimenti, devi formulare la stringa in base al riconoscimento di quali porzioni della stringa cmd.exe considera non citato a causa di un'errata interpretazione \" come delimitatori di chiusura:

      • In letterale porzioni contenenti metacaratteri della shell: ^-sfuggirgli;usando l'esempio sopra, lo è & deve essere ^-sfuggito:
        foo.exe "3\" of snow" "^& ver."

      • in porzioni con %...%riferimenti a variabili di stile:assicurarsi che cmd.exe li considera parte di a "..." corda E che i valori delle variabili non hanno virgolette incorporate e sbilanciate - cosa che non è nemmeno sempre possibile.

Per informazioni di base, continua a leggere.


Sfondo

Nota:Questo si basa sui miei esperimenti.Fammi sapere se sbaglio.

Shell simili a POSIX come Bash on Sistemi simili a Unix tokenizzare l'elenco degli argomenti (stringa) prima di passare gli argomenti individualmente al programma di destinazione:tra le altre espansioni, dividono l'elenco degli argomenti in singole parole (suddivisione delle parole) e rimuovono le virgolette dalle parole risultanti (rimozione delle virgolette). Al programma di destinazione viene consegnato un file vettore Di argomentazioni individuali, con sintattico virgolette rimosse.

Al contrario, l'interprete dei comandi di Windows apparentemente non tokenizza l'elenco degli argomenti e passa semplicemente il file separare stringa comprendente Tutto argomenti - inclusa la citazione dei caratteri.- al programma di destinazione.
Tuttavia, Alcuni la preelaborazione avviene prima che la singola stringa venga passata al programma di destinazione: ^ caratteri di fuga.al di fuori delle stringhe tra virgolette doppie vengono rimossi (sfuggono al carattere seguente) e i riferimenti a variabili (ad esempio, %USERNAME%) Sono interpolato Primo.

Pertanto, a differenza di Unix, è responsabilità del programma di destinazione analizzare la stringa degli argomenti e suddividerla in singoli argomenti rimuovendo le virgolette.Così, programmi diversi possono ipoteticamente richiedere metodi di fuga diversi E non esiste un unico meccanismo di fuga garantita per funzionare con tutti i programmi - https://stackoverflow.com/a/4094897/45375 contiene un eccellente background sull'anarchia che è l'analisi della riga di comando di Windows.

In pratica, \" è molto comune, ma NON SICURO, come menzionato sopra:

Da cmd.exe stesso non riconosce \" come un sfuggito virgolette doppie, può fraintendere i token successivi sulla riga di comando come non citato e potenzialmente interpretarli come comandi e/o reindirizzamenti di input/output.
In poche parole:il problema emerge se uno qualsiasi dei seguenti caratteri segue un apertura o sbilanciamento \": & | < >;Per esempio:

foo.exe "3\" of snow" "& ver."

cmd.exe vede i seguenti token, derivanti da un'errata interpretazione \" come una normale virgoletta doppia:

  • "3\"
  • of
  • snow" "
  • riposo: & ver.

Da cmd.exe lo pensa & ver. È non citato, lo interpreta come & (l'operatore di sequenza dei comandi), seguito dal nome di un comando da eseguire (ver. - IL . viene ignorato; ver rapporti cmd.exeinformazioni sulla versione).
L'effetto complessivo è:

  • Primo, foo.exe viene invocato con il primo 3 solo gettoni.
  • Quindi, comanda ver viene eseguito.

Anche nei casi in cui il comando accidentale non provoca danni, il comando generale non funzionerà come previsto, dato che non gli vengono passati tutti gli argomenti.

Molti compilatori/interpreti riconoscono SOLO \" - ad esempio, il compilatore GNU C/C++, Python, Perl, Ruby, persino PowerShell di Microsoft quando richiamato da cmd.exe - e, ad eccezione di PowerShell con \"", per loro non esiste una soluzione semplice a questo problema.
In sostanza, dovresti sapere in anticipo quali parti della riga di comando vengono interpretate erroneamente come non quotate e selettivamente ^-escape tutte le istanze di & | < > in quelle porzioni.

Al contrario, uso di "" è salvo, ma è purtroppo supportato solo da file eseguibili e file batch basati sul compilatore Microsoft (nel caso di file batch, con le stranezze discusse sopra), che esclude notevolmente PowerShell - vedere la sezione successiva.


Chiamando la CLI di PowerShell da cmd.exe o shell tipo POSIX:

Nota:Consulta la sezione inferiore per sapere come vengono gestiti i preventivi dentro PowerShell.

PowerShell, quando invocato da fuori - ad esempio, da cmd.exe, sia dalla riga di comando che da un file batch - riconosce soltanto \" e, anche su Windows """ e il più robusto \"" / "^"" (nonostante internamente Utilizza PowerShell ` come carattere di escape nelle stringhe tra virgolette doppie e accetta anche "" - vedere la sezione in basso):

SU finestre, chiamando da cmd.exe / un file batch:

  • "" pause, perché fondamentalmente non è supportato:

    • powershell -c " ""ab c"".length " -> errore "Nella stringa manca il terminatore"
  • \" E """ lavoro in linea di principio, ma non lo sono sicuro:

    • powershell -c " \"ab c\".length " funziona come previsto:esce 5 (notare la 2 spazi)
    • Ma non è sicuro, perché cmd.exe i metacaratteri interrompono il comando, a meno che non siano sfuggiti:
      powershell -c " \"a& c\".length " pause, dovuto al &, che dovrebbe essere sfuggito come ^&
  • \"" È sicuro, Ma normalizzare gli spazi bianchi interni, che può essere indesiderato:

    • powershell -c " \""a& c\"".length " uscite 4(!), perché i 2 spazi sono normalizzati a 1.
  • "^"" è la scelta migliore per Windows PowerShell specificamente, dove è sicuro e preserva gli spazi bianchi, ma con PowerShell Nucleo (su Windows) è lo stesso di \"", cioè spazi bianchi-normalizzante.Il merito va a Venryx per aver scoperto questo approccio

    • powershell -c " "^""a& c"^"".length " lavori:non si rompe, nonostante & - E uscite 5, ovvero spazi bianchi correttamente conservati.

    • PowerShell Nucleo: pwsh -c " "^""a& c"^"".length " lavori, ma uscite 4, cioè. normalizza gli spazi bianchi, COME \"" fa.

SU Piattaforme simili a Unix (Linux, macOS), chiamando PowerShell Nucleodella CLI, pwsh da una shell simile a POSIX come bash:

Voi dovere utilizzo \", che però lo è sia sicuro che preservando gli spazi bianchi:

$ pwsh -c " \"a&  c|\".length" # OK: 5

Informazioni correlate

  • ^ può essere utilizzato solo come carattere di escape in non citato stringhe - all'interno di stringhe tra virgolette doppie, ^ non è speciale e viene trattato alla lettera.

    • AVVERTIMENTO: Utilizzo di ^ nei parametri passati al call l'affermazione è interrotta (questo vale per entrambi gli usi di call:invocando un altro file batch o binario e chiamando una subroutine nello stesso file batch):
      • ^ istanze in virgolette doppie i valori sono inspiegabilmente raddoppiato, alterando il valore passato:ad esempio, se variabile %v% contiene valore letterale a^b, call :foo "%v%" assegna "a^^b"(!) A %1 (il primo parametro) nella subroutine :foo.
      • Non citato uso di ^ con call È rotto del tutto In ciò ^ non può più essere utilizzato per eseguire l'escape di caratteri speciali:per esempio., call foo.cmd a^&b si interrompe silenziosamente (invece di passare letterale a&b pure foo.cmd, come sarebbe il caso senza call) - foo.cmd non viene mai nemmeno invocato(!), almeno su Windows 7.
  • Sfuggire a un letterale % è un caso speciale, sfortunatamente, quale richiede una sintassi distinta a seconda che una stringa sia specificata o meno nel file riga di comando contro all'interno di un file batch;Vedere https://stackoverflow.com/a/31420292/45375

    • In breve:All'interno di un file batch, utilizzare %%.Sulla riga di comando, % non è possibile eseguire l'escape, ma se inserisci a ^ all'inizio, alla fine o all'interno del nome di una variabile in an non citato stringa (ad esempio, echo %^foo%), è possibile impedire l'espansione delle variabili (interpolazione); % le istanze sulla riga di comando che non fanno parte di un riferimento a variabile vengono trattate come valori letterali (ad esempio, 100%).
  • Generalmente, per lavorare in sicurezza con valori variabili che possono contenere spazi e caratteri speciali:

    • Incarico: Accludere Entrambi il nome della variabile e il valore in a separare coppia di virgolette doppie;per esempio., set "v=a & b" assegna un valore letterale a & b a variabile %v% (al contrario, set v="a & b" renderebbe le virgolette doppie parte del valore).Fuga letterale % istanze come %% (funziona solo nei file batch - vedi sopra).
    • Riferimento: Riferimenti di variabili tra virgolette doppie per assicurarsi che il loro valore non sia interpolato;per esempio., echo "%v%" non subordina il valore di %v% all'interpolazione e alle stampe "a & b" (ma nota che anche le virgolette doppie sono invariabilmente stampate).Al contrario, echo %v% passa letterale a A echo, interpreta & come operatore di sequenza dei comandi e quindi tenta di eseguire un comando denominato b.
      Tenere presente anche l'avvertenza di cui sopra sul riutilizzo di ^ con il call dichiarazione.
    • Esterno i programmi in genere si occupano di rimuovere le virgolette doppie attorno ai parametri, ma, come notato, nei file batch devi farlo da solo (ad esempio, %~1 per rimuovere le virgolette doppie dal primo parametro) e, purtroppo, non esiste un modo diretto che io conosca per ottenerlo echo per stampare fedelmente un valore variabile senza le virgolette doppie allegate.
      • Nei offerte UN forsoluzione alternativa basata su che funziona purché il valore non contenga virgolette doppie incorporate;per esempio.:
        set "var=^&')|;,%!" for /f "delims=" %%v in ("%var%") do echo %%~v
  • cmd.exe fa non riconoscere separare-citazioni come delimitatori di stringa: vengono trattati come valori letterali e generalmente non possono essere utilizzati per delimitare stringhe con spazi bianchi incorporati;inoltre, ne consegue che i token adiacenti alle virgolette singole e tutti i token in mezzo sono trattati come non quotati da cmd.exe e interpretato di conseguenza.

    • Tuttavia, dato che i programmi di destinazione alla fine eseguono l'analisi degli argomenti, alcuni programmi come Ruby riconoscono le stringhe tra virgolette singole anche su Windows;al contrario, gli eseguibili C/C++, Perl e Python lo fanno non riconoscerli.
      Anche se supportate dal programma target, tuttavia, non è consigliabile utilizzare stringhe tra virgolette singole, dato che il loro contenuto non è protetto da interpretazioni potenzialmente indesiderate da parte di cmd.exe.

Citando da entro PowerShell:

Windows PowerShell è una shell molto più avanzata di cmd.exe, ed è parte di Windows ormai da molti anni (e Nucleo di PowerShell ha portato l'esperienza PowerShell anche su macOS e Linux).

PowerShell funziona in modo coerente internamente per quanto riguarda la citazione:

  • all'interno di stringhe tra virgolette doppie, utilizzare `" O "" per evitare le virgolette doppie
  • all'interno di stringhe tra virgolette singole, utilizzare '' per sfuggire alle virgolette singole

Funziona sulla riga di comando di PowerShell e quando si passano parametri a script o funzioni di PowerShell entro PowerShell.

(Come discusso in precedenza, il passaggio di virgolette doppie con escape a PowerShell da fuori richiede \" o, più robusto, \"" - nient'altro funziona).

Purtroppo, quando si invoca esterno programmi da PowerShell, ti trovi di fronte alla necessità di soddisfare le regole di virgolettatura di PowerShell E scappare per il bersaglio programma:

Questo comportamento problematico è anche discusso e riassunto in questo problema con la documentazione di GitHub

Doppio-virgolette all'interno Doppio-stringhe tra virgolette:

Considera la stringa "3`" of rain", che PowerShell traduce internamente in letterale 3" of rain.

Se vuoi passare questa stringa a un programma esterno, devi applicare l'escape del programma di destinazione Inoltre a PowerShell;supponiamo che tu voglia passare la stringa a un programma C, che si aspetta che le virgolette doppie incorporate vengano sfuggite come \":

foo.exe "3\`" of rain"

Nota come Entrambi `" - per rendere felice PowerShell - E IL \ - per rendere felice il programma target - deve essere presente.

La stessa logica si applica al richiamo di un file batch, dove "" deve essere usato:

foo.bat "3`"`" of rain"

Al contrario, incorporamento separare-virgolette in a Doppio-stringa tra virgolette non richiede alcuna fuga.

Separare-virgolette all'interno separare-stringhe tra virgolette Fare non richiedere extra fuggire;prendere in considerazione '2'' of snow', che è la rappresentazione di PowerShell di 2' of snow.

foo.exe '2'' of snow'
foo.bat '2'' of snow'

PowerShell traduce le stringhe con virgolette singole in stringhe con virgolette doppie prima di passarle al programma di destinazione.

Tuttavia, Doppio-virgolette all'interno separare-stringhe tra virgolette, per il quale non è necessario fuggire PowerShell, è ancora necessario scappare per il programma di destinazione:

foo.exe '3\" of rain'
foo.bat '3"" of rain'

PowerShell v3 ha introdotto la magia --% opzione, chiamato il simbolo di interruzione dell'analisi, che allevia parte del dolore, facendo passare qualcosa dopo di esso non interpretato al programma di destinazione, salvo cmd.exe-style riferimenti a variabili d'ambiente (ad esempio, %USERNAME%), Quale Sono allargato;per esempio.:

foo.exe --% "3\" of rain" -u %USERNAME%

Nota come sfuggire al file embedded " COME \" solo per il programma di destinazione (e non anche per PowerShell come \`") è sufficiente.

Tuttavia, questo approccio:

  • non consente scappare % caratteri per evitare espansioni variabili d'ambiente.
  • preclude diretto uso di variabili ed espressioni di PowerShell;invece, la riga di comando deve essere creata in una variabile stringa in un primo passaggio e quindi invocata con Invoke-Expression in un secondo.

Pertanto, nonostante i suoi numerosi progressi, PowerShell non ha reso molto più semplice l'escape quando si chiamano programmi esterni.Tuttavia, è stato introdotto il supporto per le stringhe con virgolette singole.

Mi chiedo se sia fondamentalmente possibile nel mondo Windows passare al modello Unix lasciando che il file conchiglia eseguire tutta la tokenizzazione e la rimozione delle quote prevedibilmente, in anticipo, indipendentemente dal programma di destinazione, quindi richiamare il programma di destinazione passando i token risultanti.

In aggiunta alla di mklement0 eccellente risposta :

Quasi tutti i file eseguibili accettano \" come " sfuggito. utilizzo sicuro in cmd, tuttavia, è quasi possibile solo utilizzando DELAYEDEXPANSION.
Per inviare esplicitamente un " letterale qualche processo, assegnare \" ad una variabile di ambiente, e quindi utilizzare tale variabile, ogni volta che è necessario passare un preventivo. Esempio:

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

Nota SETLOCAL ENABLEDELAYEDEXPANSION sembra funzionare solo all'interno di file batch. Per ottenere DELAYEDEXPANSION in una sessione interattiva, avviare cmd /V:ON.

Se il vostro batchfile does't lavoro con DELAYEDEXPANSION, è possibile attivare temporaneamente:

::region without DELAYEDEXPANSION

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

::region without DELAYEDEXPANSION

Se si desidera passare il contenuto dinamico da una variabile che contiene le citazioni che sono sfuggiti come "" si può sostituire con "" \" sull'espansione:

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

Questa sostituzione non è al sicuro con l'espansione stile %...%!

In caso di OP bash -c "g++-linux-4.1 !v_params:"=\"!" è la versione sicura.


Se per qualche motivo ancora DELAYEDEXPANSION abilitazione temporanea non è un'opzione, continuate a leggere:

Utilizzando \" dall'interno cmd è un po 'più sicuro se uno ha bisogno sempre di sfuggire caratteri speciali, invece di volte. (E 'meno probabile dimenticare un accento circonflesso, se è coerente ...)

Per raggiungere questo obiettivo, uno precede ogni citazione con un accento circonflesso (^"), citazioni che dovrebbe raggiungere il processo figlio come letterali devono inoltre essere scappati con un contraccolpo (\^"). tutti meta caratteri della shell devono essere scappati con ^ pure, ad esempio, & => ^&; | => ^|; > => ^>; ecc.

Esempio:

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

Fonte: Ognuno cita argomenti della riga di comando il modo sbagliata, vedere 'un metodo migliore di citare'


Per passare il contenuto dinamico, si ha la necessità di garantire la seguente:
La parte del comando che contiene la variabile deve essere considerato "citato" di cmd.exe (Questo è impossibile se la variabile può contenere virgolette - non scrivere %var:""=\"% ). Per raggiungere questo obiettivo, l'ultima " prima della variabile e il primo " dopo la variabile non sono ^-fuggiti. cmd-metacaratteri tra questi due " non deve essere sfuggito. Esempio:

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

Questo non è sicuro, se %dynamic_content% può contenere le virgolette.

Ad esempio per Unreal strumento motore di automazione eseguito da file batch - questo ha funzionato per me

ad esempio:  -cmdline = "-Messaging" -device = dispositivo -addcmdline = "- sessionID = sessione -SessionOwner = 'proprietario' -SessionName = 'costruire' -dataProviderMode = -LogCmds locali = 'LogCommodity OFF' -execcmds Lista automazione = '; runtests test + + separati da + T1 + T2; smettere' "run

Spero che questo aiuti qualcuno, ha lavorato per me.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top