Evasione delle virgolette doppie nello script batch


91

Come dovrei 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 suoi 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, sto ottenendo 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 (cosa che fallisce in modo spettacolare).

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

Risposte:


103

Il carattere di escape negli script batch è ^. Ma per le stringhe con virgolette doppie, raddoppia le virgolette:

"string with an embedded "" character"

5
il raddoppio delle virgolette non ha funzionato per me, ma ^ ha funzionato come un campione.
davenpcj

25
^è il carattere di escape solo nelle stringhe non quotate ; nelle stringhe con virgolette doppie, viene trattato come un valore letterale. A differenza delle shell Unix (simili a POSIX), cmd.exeNON offre un trattamento shell standardizzato delle virgolette doppie all'interno di una stringa tra virgolette doppie, e l' interpretazione è lasciata al programma che viene invocato (continua nel commento successivo).
mklement0

9
(continua dal commento precedente) In pratica, la maggior parte degli eseguibili / interpreti di script applica la convenzione C di aspettarsi i "caratteri. essere sottoposto a escape come \"all'interno di una stringa tra virgolette (si applica almeno a: C / C ++, Python, Perl, Ruby). Per contro, ""è riconosciuto solo nella minoranza di casi: In parametri passati al file batch, "" è riconosciuto come incorporato virgolette, ma viene mantenuta come è nella corrispondente %<n>parametro, anche dopo aver rimosso le racchiudono virgolette con %~<n>. Python riconosce anche gentilmente "", come alternativa a \".
mklement0

89

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

Per rispondere in generale alla domanda su come evitare le virgolette doppie all'interno di una stringa tra virgolette utilizzandocmd.exe , l'interprete della riga di comando di Windows (sia sulla riga di comando - spesso ancora erroneamente chiamato "prompt DOS" - o in un file batch): Vedi in basso per uno sguardo a PowerShell .

tl; dr :

  • È necessario utilizzare"" quando si passa una stringa a un (altro) file batch e si può utilizzare ""con applicazioni create con i compilatori C / C ++ /. NET di Microsoft (che accettano anche\" ), 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 fare in modo che l'interprete dei comandi ( cmd.exe) tratti l'intera stringa tra virgolette come un singolo argomento.

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

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

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

    • \"è ciò che richiedono molti eseguibili e interpreti, incluso Windows PowerShell, quando vengono passate stringhe dall'esterno o, nel caso dei compilatori Microsoft, il supporto come alternativa a "" : in definitiva, 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 ESECUZIONE NON DESIDERATA ARBITRARIA DI COMANDI e / o RIDIREZIONI INGRESSO / USCITA :
      • I seguenti caratteri presentano questo rischio: & | < >
      • Ad esempio, quanto segue determina l'esecuzione involontaria del vercomando; vedere più avanti per una spiegazione e il prossimo punto elenco per una soluzione alternativa:
        • foo.exe "3\" of snow" "& ver."
    • Per Windows PowerShell , \""e "^""sono robusti, ma le alternative limitate (vedi sezione "Richiamo CLI di PowerShell ..." di seguito).
  • Se è necessario utilizzare \", ci sono solo 3 approcci sicuri , che sono però abbastanza ingombranti : Punta di cappello a TS per il suo aiuto.

    • Utilizzando l' espansione ritardata della variabile (possibilmente selettiva ) nel file batch, è possibile memorizzare il valore letterale \"in una variabile e fare riferimento a tale variabile all'interno di una "..."stringa utilizzando la !var!sintassi - vedere la risposta utile di TS .

      • L'approccio di cui sopra, nonostante sia ingombrante, ha il vantaggio di poterlo applicare metodicamente e che funziona in modo robusto , con qualsiasi input.
    • Solo con le stringhe LITERALI - quelle che NON coinvolgono VARIABILI - ottieni un approccio metodico simile: categoricamente ^-escape tutti i cmd.exe metacaratteri: " & | < > e - se vuoi anche sopprimere l'espansione delle variabili - %:
      foo.exe ^"3\^" of snow^" ^"^& ver.^"

    • In caso contrario, è necessario formulare la stringa in base al riconoscimento di quali parti della stringa cmd.execonsiderano non quotate a causa di un'interpretazione errata\" come delimitatori di chiusura:

      • in porzioni letterali contenenti metacaratteri di shell: ^-escape da loro; usando l'esempio sopra, è &che deve essere ^evitato:
        foo.exe "3\" of snow" "^& ver."

      • in porzioni con %...%riferimenti a variabili in stile : assicurati checmd.exe considerarli parte di una "..."stringa e che i valori delle variabili non abbiano essi stessi virgolette incorporate e sbilanciate, il 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 su sistemi Unix tokenizzano l'elenco di argomenti (stringa) prima di passare gli argomenti individualmente al programma di destinazione: tra le altre espansioni, suddividono l'elenco di argomenti in singole parole (suddivisione di parole) e rimuovono parole risultanti (rimozione delle virgolette). Al programma di destinazione viene consegnato un array di singoli argomenti , con le virgolette sintattiche rimosse .

Al contrario, l'interprete dei comandi di Windows apparentemente non tokenizza l'elenco degli argomenti e passa semplicemente la singola stringa che comprende tutti gli argomenti, comprese le virgolette. - al programma target.
Tuttavia, prima che la singola stringa venga passata al programma di destinazione , viene eseguita una preelaborazione: ^caratteri di escape. le stringhe al di fuori delle virgolette doppie vengono rimosse (escono dal carattere seguente) e i riferimenti alle variabili (ad esempio %USERNAME%) vengono interpolati per primi.

Quindi, a differenza di Unix, è responsabilità del programma di destinazione analizzare per analizzare la stringa degli argomenti e scomporla in singoli argomenti senza virgolette. Pertanto, programmi diversi possono ipoteticamente richiedere metodi di escape diversi e non esiste un unico meccanismo di escape garantito per funzionare con tutti i programmi : https://stackoverflow.com/a/4094897/45375 contiene un eccellente background sull'anarchia che è la riga di comando di Windows parsing.

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

Dal momento che di per cmd.exesé non si riconosce \"come virgolette doppie con escape , può interpretare erroneamente i token successivi sulla riga di comando come non quotati 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 è sbilanciato \" :& | < > ; per esempio:

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

cmd.exevede i seguenti token, risultanti da \"un'interpretazione errata come virgolette doppie regolari:

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

Poiché cmd.exepensa che non& ver. sia quotato , lo interpreta come &(l'operatore di sequenziamento dei comandi), seguito dal nome di un comando da eseguire ( ver.- il .viene ignorato;ver riporta cmd.exele informazioni sulla versione).
L'effetto complessivo è:

  • Primo, foo.exe viene richiamato solo con i primi 3 gettoni.
  • Quindi, comando ver viene eseguito.

Anche nei casi in cui il comando accidentale non danneggia, il tuo comando generale non funzionerà come previsto, dato che non tutti gli argomenti vengono passati ad esso.

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

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


Chiamata della CLI di PowerShell da cmd.exeshell simili a POSIX:

Nota: vedere la sezione inferiore per come vengono gestite le virgolette all'interno di PowerShell.

Quando viene richiamato dall'esterno , ad esempio da cmd.exe, dalla riga di comando o da un file batch:

  • PowerShell [Core] v6 + ora riconosce correttamente"" (oltre a\"), il che è sia sicuro da usare che preservante gli spazi .

    • pwsh -c " ""a & c"".length " non si rompe e cede correttamente 6
  • Windows PowerShell (l'edizione legacy la cui ultima versione è la 5.1) riconosce solo \" e, anche su Windows """e il più robusto \""/"^"" (anche se internamente PowerShell utilizza`come carattere di escape nelle stringhe tra virgolette e accetta anche""- vedere la sezione in basso):

Chiamata a Windows PowerShell dacmd.exe / un file batch:

  • "" si rompe , perché fondamentalmente non è supportato:

    • powershell -c " ""ab c"".length " -> errore "Nella stringa manca il terminatore"
  • \"e """ funzionano in linea di principio , ma non sono sicuri :

    • powershell -c " \"ab c\".length "funziona come previsto: esce 5(notare i 2 spazi)
    • Ma non è sicuro, perché i cmd.exemetacaratteri interrompono il comando, a meno che non vengano evitati: si
      powershell -c " \"a& c\".length " interrompe , a causa di &, che dovrebbe essere evitato come^&
  • \""è sicuro , ma normalizza gli spazi bianchi interni , il 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 in particolare , dove è sia sicuro che preserva gli spazi, ma con PowerShell Core (su Windows) è uguale alla \""normalizzazione degli spazi . Il merito va a Venryx per aver scoperto questo approccio.

    • powershell -c " "^""a& c"^"".length " funziona : non si rompe - nonostante &- e produce 5, cioè, spazi bianchi correttamente conservati.

    • PowerShell Core : pwsh -c " "^""a& c"^"".length " funziona , ma restituisce 4, cioè normalizza gli spazi , come \""fa.

Su piattaforme simili a Unix (Linux, macOS), quando si chiama la CLI di PowerShell [Core]pwsh , da una shell simile a POSIX comebash :

È necessario utilizzare\" , che, tuttavia, è sia sicuro che preservante gli spazi bianchi :

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

Informazioni correlate

  • ^può essere utilizzato solo come carattere di escape in stringhe non quotate: all'interno di stringhe tra virgolette doppie, ^non è speciale e viene trattato come un valore letterale.

    • CAVEAT : l' uso dei ^parametri in passati callall'istruzione è interrotto (questo vale per entrambi gli usi call: invocare un altro file batch o binario e chiamare una subroutine nello stesso file batch):
      • ^le istanze nei valori tra virgolette doppie vengono inspiegabilmente raddoppiate , alterando il valore passato: ad esempio, se la variabile %v%contiene un valore letterale a^b, call :foo "%v%"assegna "a^^b"(!) a %1(il primo parametro) nella subroutine :foo.
      • L' uso non quotato di ^with callè del tutto interrotto in quanto ^non può più essere utilizzato per sfuggire a caratteri speciali : ad esempio,call foo.cmd a^&binterrompe silenziosamente (invece di passarea&bancheletteralefoo.cmd, come sarebbe il caso senzacall) -foo.cmdnon viene nemmeno invocato (!), Almeno su Windows 7.
  • L'escape di un letterale %è un caso speciale , sfortunatamente, che richiede una sintassi distinta a seconda che una stringa sia specificata sulla riga di comando o all'interno di un file batch ; vedere https://stackoverflow.com/a/31420292/45375

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

    • Assegnazione : racchiudi sia il nome della variabile che il valore in una singola coppia di virgolette ; ad esempio, set "v=a & b"assegna un valore letterale a & balla variabile %v%(al contrario, set v="a & b"renderebbe le virgolette doppie parte del valore). Esci dalle %istanze letterali come %%(funziona solo nei file batch - vedi sopra).
    • Riferimento : riferimenti a virgolette doppie per assicurarsi che il loro valore non sia interpolato; ad esempio, echo "%v%"non sottopone il valore di %v%a interpolazione e stampa "a & b"(ma si noti che anche le virgolette doppie vengono invariabilmente stampate). Al contrario, echo %v%passa letterale aa echo, interpreta &come operatore di sequenziamento dei comandi e quindi cerca di eseguire un comando denominato b.
      Notare anche l'avvertenza di cui sopra il riutilizzo ^con la calldichiarazione.
    • I programmi esterni in genere si occupano di rimuovere racchiudere le virgolette attorno ai parametri, ma, come notato, nei file batch devi farlo da solo (ad esempio, %~1per rimuovere le virgolette doppie dal primo parametro) e, purtroppo, non c'è modo che io sappia per arrivare echoa stampare fedelmente un valore variabile senza le virgolette .
      • Neil offre una forsoluzione alternativa che funziona fintanto che il valore non ha virgolette doppie incorporate ; per esempio:
        set "var=^&')|;,%!" for /f "delims=" %%v in ("%var%") do echo %%~v
  • cmd.exenon non riconosce singoli -quotes per delimitare le stringhe - sono trattati come letterali e non possono generalmente essere utilizzate per le stringhe delimitano contenenti spazi; inoltre, ne consegue che i token adiacenti alle virgolette singole e gli eventuali token intermedi vengono trattati come non quotati da cmd.exee interpretati di conseguenza.

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

Citando all'interno di PowerShell:

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

PowerShell funziona internamente in modo coerente rispetto alle citazioni:

  • all'interno di stringhe tra virgolette, usa `"o ""per sfuggire alle virgolette
  • all'interno di stringhe tra virgolette singole, utilizzare ''per eseguire l'escape di virgolette singole

Funziona sulla riga di comando di PowerShell e quando si passano parametri agli script o alle funzioni di PowerShell dall'interno di PowerShell.

(Come discusso in precedenza, il passaggio di virgolette doppie con escape a PowerShell dall'esterno richiede \"o, in modo più affidabile, \""nient'altro funziona).

Purtroppo, quando si richiama esterni programmi da PowerShell, si è di fronte alla necessità di entrambi accomodate proprie regole di quoting di PowerShell e di fuggire per la destinazione del programma:

Questo comportamento problematico è anche discusso e riassunto in questa risposta

Doppia -quotes all'interno doppie corde -quoted :

Considera la stringa "3`" of rain", che viene tradotta internamente da PowerShell in letterale 3" of rain.

Se vuoi passare questa stringa a un programma esterno, devi applicare l'escape del programma di destinazione oltre a quello di PowerShell ; diciamo che vuoi passare la stringa a un programma C, che si aspetta che le virgolette doppie incorporate siano precedute da caratteri di escape come \":

foo.exe "3\`" of rain"

Si noti come sia `" - per rendere PowerShell felice - e il \- per rendere il felice programma di destinazione - deve essere presente.

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

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

Al contrario, l'incorporamento di virgolette singole in una stringa con virgolette doppie non richiede affatto l'escape.

Singolo -quotes all'interno singole stringhe -quoted non non richiedono più la fuga; considera'2'' of snow', che è la rappresentazione di PowerShell di2' of snow.

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

PowerShell converte le stringhe tra virgolette singole in virgolette doppie prima di passarle al programma di destinazione.

Tuttavia, le virgolette doppie all'interno di stringhe con virgolette singole , che non richiedono l'escape per PowerShell , devono ancora essere sottoposte a escape per il programma di destinazione :

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

PowerShell v3 ha introdotto l' --%opzione magica , chiamata simbolo di interruzione dell'analisi , che allevia parte del problema, passando qualsiasi cosa dopo che non è stata interpretata al programma di destinazione, ad eccezione dei cmd.exeriferimenti alle variabili di ambiente in stile (ad esempio %USERNAME%), che vengono espansi; per esempio:

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

Notare come l'escape di embedded "as solo \"per il programma di destinazione (e non anche per PowerShell as \`") sia sufficiente.

Tuttavia, questo approccio:

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

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

Mi chiedo se nel mondo Windows sia fondamentalmente possibile passare al modello Unix di lasciare che la shell faccia tutta la tokenizzazione e la rimozione delle quote in modo prevedibile , in anticipo , indipendentemente dal programma di destinazione , e quindi invocare il programma di destinazione passando i token risultanti .


Bella descrizione! Ma ... Literal use of ^ in double-quoted strings can, be problematic when applying ~ ...non proprio. La tilde rimuove solo le virgolette esterne se presenti. La perdita di accenti circolari è un problema della manipolazione stessa. Normalmente un set "param=%~1"risolve questo problema.
jeb

Grazie, @jeb, il problema in effetti non è specifico da usare ~- ho aggiornato la mia risposta per riflettere la mia nuova comprensione - per favore commenta, se noti un problema. Hai una spiegazione per il raddoppio ^che avviene automaticamente quando passi i parametri a callun'istruzione?
mklement0

3
Posso solo immaginare che qualcuno alla SM abbia pensato che fosse geniale. Che i caratteri doppi verranno automaticamente rimossi nella seconda fase di analisi. Ma questo è stato un grosso errore, poiché non funziona tra virgolette e impedisce efficacemente la fuga di caratteri speciali. Come call echo cat^^&dogse non fosse risolvibile con un numero qualsiasi di accenti circolari da solo
jeb

Grazie, @jeb, non avevo nemmeno considerato l' uso non citato di ^with callche, come fai notare, è gravemente rotto. Sembra che in call echo cat^&dog(singolo ^che sfugge correttamente al &) il comando target ( echo) non viene mai nemmeno invocato (!) - l'intero comando fallisce silenziosamente. Ho aggiornato la risposta di conseguenza.
mklement0

Bella risposta. Tuttavia, non lo consiglierei ""come sfuggito "ma sempre \"(vedi la mia risposta per un modo meno pericoloso di usarlo da cmd). Non conosco alcuna documentazione ufficiale che definisca ""una citazione con escape, ma almeno 2 che menzionano \": .NET e VS . Sebbene documentata in modo errato, anche l' API Win32 segue queste regole.
TS

23

Alla fine Google ha trovato la risposta. La sintassi per la sostituzione di stringhe in batch è questa:

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

Che produce "replicami". Il mio script ora ha questo aspetto:

@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 "with \", correttamente escaped per bash.


9

In aggiunta all'eccellente risposta di mklement0 :

Quasi tutti gli eseguibili accettano \"come caratteri di escape ". Tuttavia, l'utilizzo sicuro in cmd è quasi possibile solo utilizzando DELAYEDEXPANSION.
Per inviare esplicitamente un valore letterale "a un processo, assign\" a una variabile di ambiente e quindi utilizzare quella variabile, ogni volta che è necessario passare una citazione. 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, avvia cmd /V:ON.

Se il tuo file batch non funziona con DELAYEDEXPANSION, puoi abilitarlo temporaneamente:

::region without DELAYEDEXPANSION

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

::region without DELAYEDEXPANSION

Se desideri trasferire contenuto dinamico da una variabile che contiene virgolette con caratteri di escape ""che puoi sostituire ""con\" in espansione:

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

Questa sostituzione non è sicura con %...% espansione dello stile!

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


Se per qualche motivo anche l'abilitazione temporanea di DELAYEDEXPANSION non è un'opzione, continua a leggere:

Utilizzando \" dall'interno di cmd è un po 'più sicuro se è sempre necessario eseguire l'escape di caratteri speciali, invece che solo a volte. (È meno probabile che dimentichi un accento circonflesso, se è coerente ...)

Per ottenere ciò, si precede ogni virgoletta con un accento circonflesso ( ^"), le virgolette che dovrebbero raggiungere il processo figlio come letterali devono inoltre essere precedute da un backlash ( \^"). Anche TUTTI i metacaratteri della shell devono essere sottoposti a escape ^, ad esempio &=> ^&; |=> ^|; >=> ^>; eccetera.

Esempio:

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

Fonte: tutti citano gli argomenti della riga di comando nel modo sbagliato , vedere "Un metodo di citazione migliore"


Per passare il contenuto dinamico, è necessario assicurarsi quanto segue:
La parte del comando che contiene la variabile deve essere considerata "tra virgolette" cmd.exe(questo è impossibile se la variabile può contenere virgolette - non scrivere%var:""=\"% ). Per ottenere ciò, l'ultima "prima della variabile e la prima "dopo la variabile non sono ^precedute da caratteri di escape. I caratteri cmd tra questi due "non devono essere sottoposti a escape. Esempio:

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

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


Capito, grazie. Sì, l' ^escape categorica di tutti i metacaratteri funziona in modo robusto e può essere applicato in modo più metodico (ma è ovviamente un dolore reale nella parte del corpo di tua scelta). Ho aggiornato di conseguenza la mia risposta (e ti ho dato credito).
mklement0

@ mklement0 Grazie! Sì, è davvero un dolore. È fastidioso ed è ancora troppo facile dimenticare un metacarattere (quindi uso principalmente il !q!modo). Nota: la tua risposta è leggermente incoerente dopo l'ultima modifica: in alto dici: "Fai Non usare ^"". Successivamente si utilizza ^"come parte della soluzione alternativa. Forse potresti spiegare entrambi i modi? (1) Escaping di tutti i metacaratteri (più metodicamente) / (2) Escaping selettivo dei metacaratteri nelle regioni "non quotate" (a volte necessario per passare il contenuto dinamico, ad esempio foo.exe ^"danger ^& bar=\"%dynamic_content%\"^"- in questo modo la variabile viene citata per cmd)
TS

Buon punto, grazie - risposta aggiornata. Ho anche chiarito che il compilatore MS accetta sia \"e "". Ho collegato la tua risposta per l'approccio basato sulle variabili più coinvolto. Fammi sapere se ha senso adesso.
mklement0

1
@ mklement0 La tua risposta ha sempre avuto senso :-) Volevo solo dare qualche idea per possibili miglioramenti. Ho anche aggiunto l'esempio circa %dynamic_content%nella mia risposta. Pensi che sia abbastanza dettagliato o devo spiegare di più?
TS

3
Bene, grazie per avermelo fatto sapere. Buona idea per localizzare il setlocal delayedexpansion, ma dovresti terminare il blocco con endlocal(nessun argomento). Onestamente, la mia testa ha iniziato a girare guardando il tuo Gist. Abbiamo davvero a che fare con casi limite qui e penso che i futuri lettori troveranno tutto ciò di cui hanno bisogno tra le nostre due risposte.
mklement0

0

Se la stringa è già racchiusa tra virgolette, utilizza un'altra virgoletta per annullarne l'azione.

echo "Insert tablename(col1) Values('""val1""')" 

-3

Ad esempio, per lo strumento Unreal Engine Automation eseguito da file batch, questo ha funzionato per me

ad esempio: -cmdline = "-Messaging" -device = dispositivo -addcmdline = "- SessionId = session -SessionOwner = 'owner' -SessionName = 'Build' -dataProviderMode = local -LogCmds = 'LogCommunity OFF' -execcmds = 'lista di automazione ; runtest test + separati + da + T1 + T2; quit '"-run

Spero che questo aiuti qualcuno, ha funzionato per me.


Prova a distillare il concetto che hai imparato che stai cercando di condividere in un chiaro esempio, piuttosto che un lungo e per lo più non pertinente copia incolla dal tuo lavoro.
run_the_race
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.