Saltar al contenido

Cómo escapar de las cotizaciones dobles en un script por lotes

Luego de de esta extensa compilación de datos dimos con la solución esta problema que presentan algunos lectores. Te compartimos la solución y esperamos serte de gran ayuda.

Solución:

El carácter de escape en los scripts por lotes es ^. Pero para cadenas entre comillas dobles, duplique las comillas:

"string with an embedded "" character"

La propia respuesta de eplawless resuelve de manera simple y efectiva su problema específico: reemplaza todos los " instancias en toda la lista de argumentos con ", que es como Bash requiere que se representen comillas dobles dentro de una cadena entre comillas dobles.

Para responder en general a la pregunta de cómo escapar de las comillas dobles dentro de una cadena de comillas dobles usando cmd.exe, el intérprete de la línea de comandos de Windows (ya sea en la línea de comandos, a menudo llamado erróneamente “indicador de DOS”, o en un archivo por lotes):Consulte la parte inferior para ver Potencia Shell.

tl; dr:

  • usted debe usar "" al pasar una cuerda a otro) archivo por lotes y tu mayo usar "" con aplicaciones creadas con Microsoftcompiladores de C / C ++ / .NET (cuales además aceptar "), 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 obtener el intérprete de comandos (cmd.exe) para tratar toda la cadena entre comillas dobles como una soltero argumento.

      • Lamentablemente, sin embargo, no solo 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, suponiendo 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 ú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 muchos ejecutables e intérpretes exigir – incluido Windows PowerShell – cuando se pasan cadenas desde fuera – o, en el caso de Compiladores de Microsoft, soporte como alternativa a"" – en última instancia, sin embargo, depende del programa de destino analizar la lista de argumentos.
      • Ejemplo: foo.exe "We had 3" of rain."
    • SIN EMBARGO, EL USO DE " PUEDE RESULTAR EN LA EJECUCIÓN ARBITRARIA NO DESEADA DE COMANDOS y / o REDIRECCIONES DE ENTRADA / SALIDA:
      • Los siguientes caracteres presentan este riesgo: & | < >
      • Por ejemplo, lo siguiente da como resultado la ejecución no intencionada del ver mando; consulte más abajo para obtener una explicación y el siguiente punto de viñeta para una solución alternativa:
        • foo.exe "3" of snow" "& ver."
    • Para Windows PowerShell, "" y "^"" son alternativas robustas, pero limitadas (consulte la sección “Llamar a la CLI de PowerShell …” a continuación).
  • Si debe usar ", solo hay 3 a salvo enfoques, que son, sin embargo bastante engorroso: Punta del sombrero a TS por su ayuda.

    • Usando (posiblemente selectivo) expansión variable retardada en su archivo por lotes, puede almacenar literal " en un variable y hacer referencia a esa variable dentro de un "..." cadena usando !var! sintaxis – vea la útil respuesta de TS.

      • El enfoque anterior, a pesar de ser engorroso, tiene la ventaja de que puedes aplicarlo. metódicamente y que funciona robustamente, con cualquier entrada.
    • Solo con cadenas LITERALES, las que NO involucran VARIABLES, obtiene un enfoque metódico similar: categóricamente ^-escapar todoscmd.exe metacaracteres:" & | < > y, si también desea suprimir la expansión variable, %:
      foo.exe ^"3^" of snow^" ^"^& ver.^"

    • De lo contrario, debe Formule su cadena basándose en reconocer qué partes de la cadena cmd.exe considera no cotizado debido a malinterpretar " como delimitadores de cierre:

      • en literal porciones que contienen metacaracteres de shell: ^-escapar de ellos; usando el ejemplo anterior, es & eso debe ser ^-escapado:
        foo.exe "3" of snow" "^& ver."

      • en porciones con %...%-referencias de variables de estilo: asegurarse de que cmd.exe los considera parte de un "..." cuerda y que los valores de las variables no tienen comillas incrustadas y no balanceadas – que ni siquiera siempre es posible.

Para obtener información general, siga leyendo.


Fondo

Nota: Esto se basa en mis propios experimentos. Avísame si me equivoco.

Conchas similares a POSIX como Bash en Sistemas similares a Unix tokenizar la lista de argumentos (cadena) antes de pasar 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 de las palabras resultantes (eliminación de comillas). El programa de destino recibe un formación de argumentos individuales, con sintáctico comillas eliminadas.

Por el contrario, el intérprete de comandos de Windows aparentemente no tokeniza la lista de argumentos y simplemente pasa la soltero cadena que comprende todos argumentos, incluidas las citas de caracteres. – al programa de destino.

Sin embargo, algunos el preprocesamiento tiene lugar 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%) están interpolado 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 hay un único mecanismo de escape que sea garantizado para trabajar con todos los programashttps://stackoverflow.com/a/4094897/45375 contiene excelentes antecedentes sobre la anarquía que es el análisis de la línea de comandos de Windows.

En la práctica, " es muy común, pero NO ES SEGURO, como se ha mencionado más arriba:

Ya que cmd.exe en sí mismo no reconoce " como un escapado comillas dobles, puede malinterpretar tokens posteriores en la línea de comando como no cotizado y potencialmente interpretarlos como comandos y / o redirecciones de entrada / salida.
En pocas palabras: el problema surge, si alguno de los siguientes caracteres sigue un apertura o desequilibrado": & | < >; por ejemplo:

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

cmd.exe ve los siguientes tokens, como resultado de una mala interpretación " como una comilla doble regular:

  • "3"
  • of
  • snow" "
  • descansar: & ver.

Ya que cmd.exe piensa que & ver. es no cotizado, lo interpreta como & (el operador de secuencia de comandos), seguido del nombre de un comando para ejecutar (ver. – los . se ignora; ver informes cmd.exeinformación de la versión).
El efecto general es:

  • Primero, foo.exe se invoca con el primero 3 tokens solamente.
  • Entonces, comando ver es ejecutado.

Incluso en los casos en los que el comando accidental no daña, su comando general no funcionará como se diseñó, dado que no se le pasan todos los argumentos.

Muchos compiladores / intérpretes reconocen SÓLO " – por ejemplo, el compilador GNU C / C ++, Python, Perl, Ruby, incluso el propio Windows PowerShell de Microsoft cuando se invoca desde cmd.exe – y, excepto (con limitaciones) para Windows PowerShell con "", para ellos no existe una solución sencilla para 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 todas las instancias de & | < > en esas porciones.

Por el contrario, uso de "" es seguro, pero es lamentablemente, solo es compatible con archivos ejecutables y por lotes basados ​​en compiladores de Microsoft (en el caso de archivos por lotes, con las peculiaridades discutidas anteriormente), lo que excluye notablemente Potencia Shell – vea la siguiente sección.


Llamar a la CLI de PowerShell desde cmd.exe o conchas tipo POSIX:

Nota: Consulte la sección inferior para saber cómo se manejan las cotizaciones. dentro Potencia Shell.

Cuando se invoca desde fuera – por ejemplo, de cmd.exe, ya sea desde la línea de comando o desde un archivo por lotes:

  • Potencia Shell [Core] v6 + ahora reconoce correctamente "" (además de "), que es a la vez seguro de usar y preserva los espacios en blanco.

    • pwsh -c " ""a & c"".length " no se rompe y cede correctamente 6
  • Windows PowerShell (la edición heredada cuya última versión es la 5.1) reconoce solamente" y, en Windows también """ y el mas robusto "" / "^"" (aunque internamente Usos de PowerShell ` como el carácter de escape en cadenas entre comillas dobles y también acepta "" – ver sección inferior):

Vocación Windows PowerShellde cmd.exe / un archivo por lotes:

  • ""rompe, porque es fundamentalmente no compatible:

    • powershell -c " ""ab c"".length " -> error “Falta el terminador en la cadena”
  • " y """trabaja en principio, pero no lo son a salvo:

    • powershell -c " "ab c".length " funciona según lo previsto: genera 5 (nota la 2 espacios)
    • Pero no es seguro, porque cmd.exe los metacaracteres rompen el comando, a menos que se escapen:
      powershell -c " "a& c".length "rompe, debido a la &, que tendría que escaparse como ^&
  • "" es a salvo, pero normalizar el espacio en blanco interior, que puede no ser deseado:

    • powershell -c " ""a& c"".length " salidas 4(!), 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 Centro (en Windows) es lo mismo que "", es decir, espacios en blanconormalizando. El crédito es para Venryx por descubrir este enfoque.

    • powershell -c " "^""a& c"^"".length "obras: no se rompe – a pesar de &y salidas 5, es decir, espacios en blanco correctamente conservados.

    • Potencia Shell Centro: pwsh -c " "^""a& c"^"".length "obras, pero salidas 4, es decir normaliza los espacios en blanco, como "" lo hace.

Sobre Plataformas tipo Unix (Linux, macOS), al llamar Potencia Shell [Core]CLI de pwsh, desde un shell similar a POSIX como bash:

usted debe usar ", que, sin embargo, es tanto seguro como que preserva los espacios en blanco:

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

Información relacionada

  • ^ solo se puede utilizar como carácter de escape en no cotizado instrumentos de cuerda – dentro de cadenas entre comillas dobles, ^ no es especial y se trata como literal.

    • CONSIDERACIÓN: Uso de ^ en los parámetros pasados ​​al call la declaración está rota (esto se aplica a ambos usos de call: invocando otro archivo por lotes o binario y llamando a una subrutina en el mismo archivo por lotes):
      • ^ instancias en entre comillas los valores son inexplicablemente duplicado, alterando el valor que se pasa: por ejemplo, si la variable %v% contiene valor literal a^b, call :foo "%v%" asigna "a^^b"(!) para %1 (el primer parámetro) en subrutina :foo.
      • No cotizado uso de ^ con call es roto por completo en eso ^ ya no se puede usar para escapar de caracteres especiales: p.ej, call foo.cmd a^&b rompe silenciosamente (en lugar de pasar literal a&b también foo.cmd, como sería el caso sin call) – foo.cmd ni siquiera se invoca (!), al menos en Windows 7.
  • Escapar de un literal % es un caso especial, desafortunadamente, que requiere una sintaxis distinta dependiendo de si se especifica una cadena en el línea de comando vs. dentro de un archivo por lotes; ver https://stackoverflow.com/a/31420292/45375

    • En resumen: dentro de un archivo por lotes, use %%. En la línea de comando, % no se puede escapar, pero si coloca un ^ al principio, al final o dentro de un nombre de variable en un no cotizado cadena (p. ej., echo %^foo%), puede evitar la expansión variable (interpolación); % Las instancias en la línea de comando que no forman parte de una referencia de variable se tratan como literales (p. ej., 100%).
  • Generalmente, para trabajar de forma segura con valores variables que pueden contener espacios y caracteres especiales:

    • Asignación: Encerrar ambos el nombre de la variable y el valor en un soltero par de comillas dobles; p.ej, set "v=a & b" asigna valor literal a & b a variable %v% (por el contrario, set v="a & b" haría que las comillas dobles formen parte del valor). Escape literal % instancias como %% (funciona solo en archivos por lotes; consulte más arriba).
    • Referencia: Referencias de variables de comillas dobles para asegurarse de que su valor no esté interpolado; p.ej, echo "%v%" no sujeta 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 literal a para echo, interpreta & como el operador de secuenciación de comandos y, por lo tanto, intenta ejecutar un comando llamado b.
      También tenga en cuenta la advertencia anterior sobre la reutilización de ^ con el call declaración.
    • Externo Los programas generalmente se encargan de eliminar las comillas dobles que encierran los parámetros, pero, como se señaló, en los archivos por lotes debe hacerlo usted mismo (por ejemplo, %~1 para eliminar las comillas dobles adjuntas del primer parámetro) y, lamentablemente, no hay forma directa que yo sepa de conseguir echo para imprimir un valor variable fielmente sin las comillas dobles adjuntas.
      • Ofertas de Neil a 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 lo hace no reconocer soltero-citas como delimitadores de cadenas: se tratan como literales y, por lo general, no se pueden utilizar para delimitar cadenas 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 por cmd.exe e interpretado en consecuencia.

    • Sin embargo, dado que los programas de destino en última instancia realizan su propio análisis de argumentos, algunos programas como Ruby reconocen cadenas entre comillas simples incluso en Windows; por el contrario, los ejecutables de C / C ++, Perl y Python no reconocerlos.
      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 de dentro de Potencia Shell:

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 la cotización:

  • dentro de cadenas entre comillas dobles, utilice `" o "" para escapar de las comillas dobles
  • dentro de cadenas entre comillas simples, use '' para escapar de las comillas simples

Esto funciona en la línea de comandos de PowerShell y al pasar parámetros a scripts o funciones de PowerShell desde dentro de Potencia Shell.

(Como se discutió anteriormente, pasar una comilla doble de escape a PowerShell desde fuera requiere " o, de forma más robusta, "" – nada más funciona).

Lamentablemente, al invocar externo programas de PowerShell, se enfrenta a la necesidad de adaptarse a las propias reglas de cotización de PowerShell y escapar por el objetivo programa:

Este comportamiento problemático también se discute y se resume en esta respuesta.

Doble-citas en el interior doble-cadenas entre comillas:

Considere la cuerda "3`" of rain", que PowerShell traduce internamente a literal 3" of rain.

Si desea pasar esta cadena a un programa externo, tienes que aplicar el escape del programa de destino además a PowerShell’s; digamos que desea pasar la cadena a un programa en C, que espera que las comillas dobles incrustadas se escapen como ":

foo.exe "3`" of rain"

Note como ambos`" – para hacer feliz a PowerShell – y los – para hacer feliz al programa objetivo – debe estar presente.

La misma lógica se aplica a la invocación de un archivo por lotes, donde "" debe ser usado:

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

Por el contrario, incrustar soltero-citas en un doble-cadena entre comillas no requiere escapar en absoluto.

Soltero-citas en el interior soltero-cadenas entre comillas hacer no exigir extra escapando considerar '2'' of snow', que es la representación de PowerShell de 2' of snow.

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

PowerShell traduce cadenas entre comillas simples en comillas dobles antes de pasarlas al programa de destino.

Sin embargo, doble-citas en el interior soltero-cadenas entre comillas, que no necesitan escapar para Potencia Shell, todavía es necesario escapar para el programa de destino:

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

Potencia Shell v3 introdujo la magia --% opción, llamó al símbolo de parada de análisis, que alivia algo del dolor, pasando algo después sin interpretar al programa de destino, excepto para cmd.exereferencias de variables de entorno de estilo (p. ej., %USERNAME%), cuales están expandido; p.ej:

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

Tenga en cuenta cómo escapar del incrustado " como " solo para el programa de destino (y no también para PowerShell como `") es suficiente.

Sin embargo, este enfoque:

  • no permite escapando% caracteres para evitar expansiones de variables de entorno.
  • excluye directo uso de variables y expresiones de PowerShell; en su lugar, la línea de comando debe construirse en una variable de cadena en un primer paso, y luego invocarse con 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 cascarón hacer toda la tokenización y eliminación de cotizaciones predeciblemente, en la delantera, independientemente del programa objetivo, y luego invocar el programa de destino pasando los tokens resultantes.

A Google finalmente se le ocurrió la respuesta. La sintaxis para el reemplazo de cadenas por lotes es la siguiente:

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

Lo que produce “replicarme”. Mi secuencia de comandos ahora se ve así:

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

Que reemplaza todas las instancias de " con ", escapó correctamente para bash.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *