¿Cómo haría para reemplazar todas las comillas dobles en los parámetros de mi archivo por lotes con comillas dobles de escape? Este es mi archivo por lotes actual, que expande todos sus parámetros de línea de comando dentro de la cadena:
@echo off
call bash --verbose -c "g++-linux-4.1 %*"
Luego usa esa cadena para hacer una llamada al bash de Cygwin, ejecutando un compilador cruzado de Linux. Desafortunadamente, recibo parámetros como estos pasados a mi archivo por lotes:
"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"
Donde la primera cita alrededor de la primera ruta pasada es terminar prematuramente la cadena que se pasa a GCC y pasar el resto de los parámetros directamente a bash (que falla espectacularmente).
Me imagino que si puedo concatenar los parámetros en una sola cadena y luego escapar de las comillas, debería funcionar bien, pero tengo dificultades para determinar cómo hacerlo. ¿Alguien sabe?
fuente
^
es el carácter de escape solo en cadenas sin comillas ; en cadenas entre comillas dobles, se trata como un literal. A diferencia de los shells de Unix (tipo POSIX),cmd.exe
NO ofrece un tratamiento de shell estandarizado de comillas dobles dentro de una cadena de comillas dobles, y la interpretación se deja al programa que se invoca (continúa en el siguiente comentario)."
caracteres. para escapar como\"
dentro de una cadena entre comillas dobles (se aplica al menos a: C / C ++, Python, Perl, Ruby). Por el contrario,""
solo se reconoce en una minoría de casos: en los parámetros pasados a archivos por lotes,""
se reconoce como un incrustado doble cita, pero está retenido como es en el correspondiente%<n>
parámetro, incluso después de la eliminación de los que encierran entre comillas dobles con%~<n>
. Python amablemente también reconoce""
, como una alternativa a\"
.La propia respuesta de eplawless resuelve de manera simple y efectiva su problema específico: reemplaza todas las
"
instancias en la lista completa de argumentos con\"
, que es como Bash requiere que las comillas dobles dentro de una cadena de comillas dobles sean representadas.Para responder en general a la pregunta de cómo escapar de las comillas dobles dentro de una cadena entre comillas dobles utilizando
cmd.exe
, el intérprete de línea de comandos de Windows (ya sea en la línea de comandos, a menudo todavía llamado erróneamente "indicador de DOS", o en un archivo por lotes): Consulte la parte inferior para ver PowerShell .tl; dr :
Usted debe utilizar
""
cuando se pasa una cadena a un (tro) archivo por lotes y se puede utilizar""
con las aplicaciones creadas con Microsoft C 's / C ++ / compiladores NET. (Que también acepta\"
), que en Windows incluye Python y Node.js :Ejemplo:
foo.bat "We had 3"" of rain."
Lo siguiente se aplica solo a los archivos por lotes:
""
es la única forma de hacer que el comando interpreter (cmd.exe
) trate toda la cadena entre comillas dobles como un solo argumento.Lamentablemente, sin embargo, no sólo se conservan las comillas dobles adjuntas (como de costumbre), sino también las dobles con escape, por lo que obtener la cadena deseada es un proceso de dos pasos; por ejemplo, asumiendo que la cadena entre comillas dobles se pasa como el primer argumento
%1
,:set "str=%~1"
elimina las comillas dobles adjuntas;set "str=%str:""="%"
luego convierte las comillas dobles duplicadas en simples.Asegúrese de utilizar las comillas dobles adjuntas alrededor de las partes de la asignación para evitar una interpretación no deseada de los valores.
\"
es requerido - como la única opción - por muchos otros programas , (por ejemplo, Ruby, Perl, e incluso el propio Windows PowerShell de Microsoft (!)), pero SU USO NO ES SEGURO :\"
es lo que requieren muchos ejecutables e intérpretes , incluido Windows PowerShell, cuando se pasan cadenas desde el exterior , o, en el caso de los compiladores de Microsoft, soporte como alternativa a""
, en última instancia, sin embargo, depende del programa de destino analizar la lista de argumentos .foo.exe "We had 3\" of rain."
\"
PUEDE RESULTAR EN LA EJECUCIÓN ARBITRARIA NO DESEADA DE COMANDOS y / o REDIRECCIONES DE ENTRADA / SALIDA :& | < >
ver
comando; vea más abajo para una explicación y el siguiente punto de viñeta para una solución alternativa:foo.exe "3\" of snow" "& ver."
\""
y"^""
son alternativas sólidas pero limitadas (consulte la sección "Llamar a la CLI de PowerShell ..." a continuación).Si debe usar
\"
, solo hay 3 enfoques seguros , que son, sin embargo, bastante engorrosos : Punta del sombrero a TS por su ayuda.Al usar la expansión de variable retardada (posiblemente selectiva ) en su archivo por lotes, puede almacenar literal
\"
en una variable y hacer referencia a esa variable dentro de una"..."
cadena usando la!var!
sintaxis ; consulte la útil respuesta de TS .Solo con cadenas LITERALES, las que NO involucran VARIABLES, obtiene un enfoque metódico similar: categóricamente,
^
escapar de todos loscmd.exe
metacaracteres:" & | < >
y, si también desea suprimir la expansión de variables%
:foo.exe ^"3\^" of snow^" ^"^& ver.^"
De lo contrario, debe formular su cadena basándose en el reconocimiento de qué partes de la cadena se
cmd.exe
consideran sin comillas debido a una mala interpretación\"
como delimitadores de cierre:en porciones literales que contienen metacaracteres de shell:
^
-escape de ellos; usando el ejemplo anterior, es&
que se debe^
escapar:foo.exe "3\" of snow" "^& ver."
en porciones con
%...%
referencias de variable de estilo : asegúrese de que lascmd.exe
considera parte de una"..."
cadena y que los valores de las variables no tienen comillas incrustadas y no balanceadas, lo que ni siquiera siempre es posible .Para obtener información general, siga leyendo.
Antecedentes
Nota: Esto se basa en mis propios experimentos. Avísame si me equivoco.
Los shells similares a POSIX, como Bash en sistemas similares a Unix, tokenizan la lista de argumentos (cadena) antes de pasar los argumentos individualmente al programa de destino: entre otras expansiones, dividen la lista de argumentos en palabras individuales (división de palabras) y eliminan los caracteres entre comillas del palabras resultantes (eliminación de comillas). El programa de destino recibe una serie de argumentos individuales , sin comillas sintácticas .
Por el contrario, el intérprete de comandos de Windows aparentemente no tokeniza la lista de argumentos y simplemente pasa la cadena única que comprende todos los argumentos, incluidos los caracteres entre comillas. - al programa de destino.
Sin embargo, se realiza un procesamiento previo antes de que la cadena única se pase al programa de destino:
^
caracteres de escape. fuera de las cadenas entre comillas dobles se eliminan (escapan al siguiente carácter), y las referencias de variables (por ejemplo,%USERNAME%
) se interpolan primero.Por lo tanto, a diferencia de Unix, es responsabilidad del programa de destino analizar para analizar la cadena de argumentos y dividirla en argumentos individuales sin las comillas. Por lo tanto, diferentes programas pueden requerir hipotéticamente diferentes métodos de escape y no existe un mecanismo de escape único que esté garantizado para funcionar con todos los programas : https://stackoverflow.com/a/4094897/45375 contiene una excelente información sobre la anarquía que es la línea de comandos de Windows. análisis.
En la práctica,
\"
es muy común, pero NO SEGURO , como se mencionó anteriormente:Dado que en
cmd.exe
sí mismo no se reconoce\"
como una comilla doble de escape , puede malinterpretar los tokens posteriores en la línea de comando como sin comillas y potencialmente interpretarlos como comandos y / o redirecciones de entrada / salida .En pocas palabras: las superficies de problema, si cualquiera de los siguientes caracteres siguen una abertura o desequilibrada
\"
:& | < >
; por ejemplo:cmd.exe
ve los siguientes tokens, que resultan de una mala interpretación\"
como una comilla doble regular:"3\"
of
snow" "
& ver.
Como
cmd.exe
piensa que no& ver.
está entre comillas , lo interpreta como&
(el operador de secuencia de comandos), seguido del nombre de un comando a ejecutar (ver.
-.
se ignora;ver
informacmd.exe
la información de la versión).El efecto general es:
foo.exe
se invoca solo con los primeros 3 tokens.ver
se ejecuta el comando .Incluso en los casos en que el comando accidental no daña, su comando general no funcionará como fue diseñado, dado que no se le pasan todos los argumentos.
Muchos compiladores / intérpretes SÓLO reconocen
\"
, por ejemplo, el compilador GNU C / C ++, Python, Perl, Ruby, incluso el propio Windows PowerShell de Microsoft cuando se invoca desdecmd.exe
, y, excepto (con limitaciones) para Windows PowerShell\""
, para ellos no existe una solución simple a este problema.Esencialmente, tendría que saber de antemano qué partes de su línea de comando se malinterpretan como sin comillas y, de forma selectiva,
^
escapar de todas las instancias de& | < >
en esas partes.Por el contrario, el uso de
""
es SEGURO , pero lamentablemente solo es compatible con archivos ejecutables y por lotes basados en el compilador de Microsoft (en el caso de los archivos por lotes, con las peculiaridades mencionadas anteriormente), lo que excluye a PowerShell. ; consulte la siguiente sección.Llamar a la CLI de PowerShell desde
cmd.exe
o shells similares a POSIX:Nota: Consulte la sección inferior para ver cómo se manejan las cotizaciones dentro de PowerShell.
Cuando se invoca desde el exterior , por ejemplo, desde
cmd.exe
, ya sea desde la línea de comando o desde un archivo por lotes:PowerShell [Core] v6 + ahora reconoce correctamente
""
(además de\"
), que es seguro de usar y preserva los espacios en blanco .pwsh -c " ""a & c"".length "
no se rompe y cede correctamente6
Windows PowerShell (la edición heredada cuya última versión es 5.1) reconoce solo
\"
y, en Windows también"""
y el más robusto\""
/"^""
(aunque internamente PowerShell usa`
como carácter de escape en cadenas entre comillas dobles y también acepta""
; consulte la sección inferior):Llamar a Windows PowerShell desde
cmd.exe
/ un archivo por lotes:""
se rompe , porque es fundamentalmente no compatible:powershell -c " ""ab c"".length "
-> error "Falta el terminador en la cadena"\"
y"""
funcionan en principio , pero no son seguros :powershell -c " \"ab c\".length "
funciona según lo previsto: produce5
(tenga en cuenta los 2 espacios)cmd.exe
metacaracteres rompen el comando, a menos que se escape: sepowershell -c " \"a& c\".length "
rompe , debido al&
, que tendría que escaparse como^&
\""
es seguro , pero normaliza el espacio en blanco interior , lo que puede no ser deseado:powershell -c " \""a& c\"".length "
salidas4
(!), porque los 2 espacios están normalizados a 1."^""
es la mejor opción para Windows PowerShell específicamente , donde es seguro y conserva los espacios en blanco, pero con PowerShell Core (en Windows) es lo mismo que\""
, es decir, normalización de espacios en blanco . El crédito es para Venryx por descubrir este enfoque.powershell -c " "^""a& c"^"".length "
funciona : no se rompe - a pesar&
- y produce5
, es decir, espacios en blanco correctamente conservados.PowerShell Core :
pwsh -c " "^""a& c"^"".length "
funciona , pero genera4
, es decir, normaliza los espacios en blanco , como lo\""
hace.En plataformas similares a Unix (Linux, macOS), al llamar a la CLI de PowerShell [Core]
pwsh
, desde un shell similar a POSIX comobash
:Usted debe utilizar
\"
, que, sin embargo, es seguro y los espacios en blanco de preservación :Información relacionada
^
solo se puede usar como carácter de escape en cadenas sin comillas ; dentro de cadenas entre comillas dobles,^
no es especial y se trata como un literal.^
parámetros in pasados a lacall
declaración está roto (esto se aplica a ambos usos decall
: invocar otro archivo por lotes o binario y llamar a una subrutina en el mismo archivo por lotes):^
las instancias en valores entre comillas dobles se duplican inexplicablemente , alterando el valor que se pasa: por ejemplo, si la variable%v%
contiene un valor literala^b
,call :foo "%v%"
asigna"a^^b"
(!) a%1
(el primer parámetro) en la subrutina:foo
.^
concall
se interrumpe por completo, ya que^
ya no se puede usar para escapar de caracteres especiales : por ejemplo,call foo.cmd a^&b
se rompe silenciosamente (en lugar de pasar literala&b
tambiénfoo.cmd
, como sería el caso sincall
),foo.cmd
nunca se invoca (!), Al menos en Windows 7.%
Desafortunadamente, escapar de un literal es un caso especial que requiere una sintaxis distinta dependiendo de si se especifica una cadena en la línea de comando o dentro de un archivo por lotes ; ver https://stackoverflow.com/a/31420292/45375%%
. En la línea de comando,%
no se puede escapar, pero si coloca un^
al principio, al final o dentro del nombre de una variable en una cadena sin comillas (por ejemplo,echo %^foo%
), puede evitar la expansión de la variable (interpolación);%
las instancias en la línea de comando que no son parte de una referencia de variable se tratan como literales (por ejemplo,100%
).Generalmente, para trabajar de forma segura con valores de variables que pueden contener espacios y caracteres especiales :
set "v=a & b"
asigna un valor literala & b
a la variable%v%
(por el contrario,set v="a & b"
las comillas dobles forman parte del valor). Escapa de las%
instancias literales como%%
(funciona solo en archivos por lotes; consulte más arriba).echo "%v%"
no somete el valor de%v%
a la interpolación y las impresiones"a & b"
(pero tenga en cuenta que las comillas dobles también se imprimen invariablemente). Por el contrario,echo %v%
pasa literala
aecho
, interpreta&
como el operador de secuencia de comandos y, por lo tanto, intenta ejecutar un comando llamadob
.También tenga en cuenta la advertencia anterior sobre el uso de
^
lacall
declaración.%~1
para eliminar las comillas dobles adjuntas del primer parámetro) y, lamentablemente, no hay manera que conozcoecho
para imprimir un valor variable fielmente sin las comillas dobles adjuntas .for
solución alternativa que funciona siempre que el valor no tenga comillas dobles incrustadas ; p.ej:set "var=^&')|;,%!" for /f "delims=" %%v in ("%var%") do echo %%~v
cmd.exe
no no reconocer individuales -quotes como delimitadores de cadenas - que son tratados como literales y en general no pueden ser usados para cuerdas delimitan con espacios en blanco incrustados; Además, se deduce que los tokens que lindan con las comillas simples y los tokens intermedios se tratan como no citados porcmd.exe
y se interpretan en consecuencia.Sin embargo, incluso si es compatible con el programa de destino, no es aconsejable utilizar cadenas entre comillas simples, dado que su contenido no está protegido de interpretaciones potencialmente no deseadas por
cmd.exe
.Citando desde dentro de PowerShell:
Windows PowerShell es un shell mucho más avanzado que
cmd.exe
, y ha sido parte de Windows durante muchos años (y PowerShell Core también trajo la experiencia de PowerShell a macOS y Linux).PowerShell funciona de forma coherente internamente con respecto a las citas:
`"
o""
para escapar de las comillas dobles''
para escapar de las comillas simplesEsto funciona en la línea de comandos de PowerShell y al pasar parámetros a scripts o funciones de PowerShell desde dentro de PowerShell.
(Como se mencionó anteriormente, pasar una comilla doble de escape a PowerShell desde el exterior requiere
\"
o, de manera más sólida,\""
nada más funciona).Lamentablemente, al invocar programas externos desde PowerShell, se enfrenta a la necesidad de adaptarse a las propias reglas de cotización de PowerShell y escapar al programa de destino :
Este comportamiento problemático también se discute y se resume en esta respuesta.
Doble -quotes dentro de dobles cadenas -quoted :
Considere una cadena
"3`" of rain"
, que PowerShell traduce internamente a literal3" of rain
.Si desea pasar esta cadena a un programa externo, debe aplicar el escape del programa de destino además del de PowerShell ; digamos que desea pasar la cadena a un programa en C, que espera que las comillas dobles incrustadas se escapen como
\"
:Tenga en cuenta que ambos
`"
, para hacer feliz a PowerShell, y el\
, para hacer feliz al programa de destino, deben estar presentes.La misma lógica se aplica a la invocación de un archivo por lotes, donde se
""
debe utilizar:Por el contrario, incrustar comillas simples en una cadena de comillas dobles no requiere ningún tipo de escape.
Individuales -quotes dentro individuales cadenas -quoted no no requerir extra de escape; considere
'2'' of snow'
, que es la representación de PowerShell de2' of snow
.PowerShell traduce cadenas entre comillas simples en comillas dobles antes de pasarlas al programa de destino.
Sin embargo, las comillas dobles dentro de cadenas entre comillas simples , que no necesitan escapar para PowerShell , aún deben escaparse para el programa de destino :
PowerShell v3 introdujo la
--%
opción mágica , llamada símbolo de detener el análisis , que alivia parte del dolor, al pasar cualquier cosa después de que no se interprete al programa de destino, exceptocmd.exe
las referencias de variables de entorno de estilo (por ejemplo,%USERNAME%
), que se expanden; p.ej:Tenga en cuenta que es suficiente escapar del incrustado
"
como solo\"
para el programa de destino (y no también para PowerShell como\`"
).Sin embargo, este enfoque:
%
para evitar expansiones de variables de entorno.Invoke-Expression
en un segundo.Por lo tanto, a pesar de sus muchos avances, PowerShell no ha facilitado mucho el escape al llamar a programas externos. Sin embargo, ha introducido soporte para cadenas de comillas simples.
Me pregunto si es fundamentalmente posible en el mundo de Windows cambiar alguna vez al modelo Unix de dejar que el shell haga toda la tokenización y la eliminación de cotizaciones de manera predecible , por adelantado , independientemente del programa de destino , y luego invocar el programa de destino pasando los tokens resultantes .
fuente
Literal use of ^ in double-quoted strings can, be problematic when applying ~ ...
no realmente. La tilde solo elimina las comillas externas cuando están presentes. La pérdida de intercalaciones es un problema de manejo en sí. Normalmente, unset "param=%~1"
resuelve esto.~
. He actualizado mi respuesta para reflejar mi nueva comprensión. Por favor, comente, si detecta un problema. ¿Tiene una explicación para la duplicación^
que ocurre automáticamente cuando pasa parámetros a unacall
declaración?call echo cat^^&dog
si no se pudiera resolver con ninguna cantidad de intercalaciones solo^
withcall
, que, como señala, está muy roto. Parece que encall echo cat^&dog
(single^
que escapa correctamente al&
) el comando de destino (echo
) ni siquiera se invoca (!) - el comando completo falla silenciosamente. Actualicé la respuesta en consecuencia.""
como escapado,"
pero siempre\"
(consulte mi respuesta para conocer una forma menos peligrosa de usarlo desde cmd). No sé ninguna documentación oficial que define""
como un escaparon cita, pero por lo menos 2 que mencionan\"
: .NET y VS . Aunque está mal documentado, la API de Win32 también sigue estas reglas.Google finalmente encontró la respuesta. La sintaxis para el reemplazo de cadenas por lotes es la siguiente:
Lo que produce "replicame". Mi secuencia de comandos ahora se ve así:
Lo que reemplaza todas las instancias de
"
with\"
, correctamente escapado para bash.fuente
Como complemento a la excelente respuesta de mklement0 :
Casi todos los ejecutables aceptan
\"
como escapado"
. Sin embargo, el uso seguro en cmd casi solo es posible con DELAYEDEXPANSION.Para enviar explícitamente un literal
"
a algún proceso, asigne\"
una variable de entorno y luego use esa variable, siempre que necesite pasar una cita. Ejemplo:Note
SETLOCAL ENABLEDELAYEDEXPANSION
parece funcionar solo en archivos por lotes. Para obtener EXPANSIÓN RETARDADA en una sesión interactiva, comiencecmd /V:ON
.Si su archivo por lotes no funciona con DELAYEDEXPANSION, puede habilitarlo temporalmente:
Si desea pasar contenido dinámico de una variable que contiene comillas que se escapan, ya
""
que puede reemplazar""
con una\"
expansión:¡Este reemplazo no es seguro con la
%...%
expansión de estilo!En caso de OP
bash -c "g++-linux-4.1 !v_params:"=\"!"
es la versión segura.Si por alguna razón, incluso habilitar temporalmente la EXPANSIÓN RETARDADA no es una opción, siga leyendo:
Usar
\"
desde dentro de cmd es un poco más seguro si siempre se necesita escapar de los caracteres especiales, en lugar de solo algunas veces. (Es menos probable que olvide un símbolo de intercalación, si es consistente ...)Para lograr esto, una cita precede con un signo de intercalación (
^"
), las comillas que deben llegar al proceso hijo como literales deben escaparse adicionalmente con una reacción (\^"
). TODOS los metacaracteres de shell también deben tener un escape^
, por ejemplo&
=>^&
;|
=>^|
;>
=>^>
; etc.Ejemplo:
Fuente: Todo el mundo cita los argumentos de la línea de comandos de forma incorrecta , consulte "Un método mejor para citar".
Para pasar contenido dinámico, es necesario asegurarse de lo siguiente:
La parte del comando que contiene la variable debe ser considerada "entre comillas" por
cmd.exe
(Esto es imposible si la variable puede contener comillas, no escriba%var:""=\"%
). Para lograr esto, el último"
antes de la variable y el primero"
después de la variable no se^
escapan. cmd-metacaracteres entre esos dos"
no deben escaparse. Ejemplo:Esto no es seguro, si
%dynamic_content%
puede contener citas que no coinciden.fuente
^
escapar categóricamente de todos los metacaracteres funciona de manera sólida y se puede aplicar de manera más metódica (sin embargo, obviamente es un dolor real en la parte del cuerpo que elijas). He actualizado mi respuesta en consecuencia (y le he dado crédito).!q!
forma). Nota: Su respuesta es un poco incoherente después de su última edición: Cerca de la parte superior que dice: "No , no use^"
". Más tarde, lo utilizará^"
como parte de la solución alternativa. ¿Quizás podrías explicar ambas cosas? (1) Escapando de todos los metacaracteres (más metódicamente) / (2) Escapando selectivamente de los metacaracteres en regiones "sin comillas" (a veces es necesario para pasar contenido dinámico, pfoo.exe ^"danger ^& bar=\"%dynamic_content%\"^"
. Ej ., De esta manera la variable se cita para cmd)\"
y""
. Me he vinculado a su respuesta para el enfoque basado en variables más complicado. Déjame saber si tiene sentido ahora.%dynamic_content%
en mi respuesta. ¿Crees que es lo suficientemente detallado o tengo que explicar más?setlocal delayedexpansion
, pero debe terminar el bloque conendlocal
(sin argumento). Honestamente, mi cabeza comenzó a dar vueltas al mirar tu esencia. Realmente estamos lidiando con casos extremos aquí, y creo que los futuros lectores encontrarán todo lo que necesitan entre nuestras dos respuestas.Si la cadena ya está entre comillas, utilice otra comilla para anular su acción.
fuente
Por ejemplo, para la herramienta Unreal Engine Automation que se ejecuta desde un archivo por lotes, esto funcionó para mí
Por ejemplo: -cmdline = "-Messaging" -device = device -addcmdline = "- SessionId = session -SessionOwner = 'owner' -SessionName = 'Build' -dataProviderMode = local -LogCmds = 'LogCommodity OFF' -execcmds = 'lista de automatización ; ejecuta pruebas + separadas + por + T1 + T2; salir '"-run
Espero que esto ayude a alguien, funcionó para mí.
fuente