Pergunta

Como eu iria sobre a substituição de todas as aspas duplas nos parâmetros do meu arquivo de lote com aspas duplas escaparam? Este é o meu atual arquivo de lote, que se expande todos os seus parâmetros de linha de comando dentro da string:

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

Em seguida, usa essa corda para fazer uma chamada para a festança da Cygwin, executando um cross-compilador Linux. Infelizmente, eu estou recebendo parâmetros como estes passaram no meu arquivo de lote:

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

Quando a primeira citação em torno do primeiro caminho aprovada em está terminando prematuramente a corda que está sendo passado para GCC, e passando o resto dos parâmetros diretamente para bash (que falhar espetacularmente.)

Eu imagino se eu pode concatenar os parâmetros em uma única seqüência, em seguida, fugir das citações ele deve funcionar bem, mas eu estou tendo dificuldade em determinar como fazer isso. Alguém sabe?

Foi útil?

Solução 3

O Google finalmente veio com a resposta. A sintaxe para substituição de string em lote é o seguinte:

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

Que produz "replicar-me". Meu script agora se parece com isso:

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

que substitui todas as instâncias do " com \", corretamente escapou para a festança.

Outras dicas

O caractere de escape em scripts em lotes é ^. Mas para strings delimitadas por aspas, dobrar as aspas:

"string with an embedded "" character"

de eplawless própria resposta simples e eficaz resolve o seu problema específico: ele substitui todas as instâncias " em toda a lista de argumentos com \" , que é como Bash requer aspas dentro de uma string entre aspas para ser representado.

Para geralmente responder à pergunta de como escapar aspas dentro de uma string entre aspas usando cmd.exe , o intérprete de linha de comando do Windows (seja na linha de comando - muitas vezes ainda chamado erroneamente de " DOS prompt" - ou em um arquivo de lote): Veja a parte inferior para um olhar para PowerShell

.

tl; dr :

  • Você deve uso "" quando passar uma string para um (nother) arquivo de lote e você pode uso "" com aplicativos criados com o Microsoft 's C / C ++ /. compiladores NET (que também aceitar \"), que no Windows inclui Python e Node.js :

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

    • O seguinte se aplica a arquivos em lote apenas:

      • "" é a única maneira de obter o interpretador de comandos (cmd.exe) para tratar a seqüência inteira entre aspas como um única argumento.

      • Infelizmente, no entanto, não são apenas as que encerram aspas retidos (como de costume), mas assim são as duplicou que escaparam, por isso, obter a seqüência pretendida é um processo de duas etapas; por exemplo, supondo que a string entre aspas é passada como o 1º argumento, %1:

      • set "str=%~1" remove as que encerram aspas; set "str=%str:""="%" seguida, converte o aspas para os solteiros dobrou.
        Certifique-se de usar as que encerram aspas em torno das peças de atribuição para evitar interpretação indesejada dos valores.

  • \" é necessário - como a única opção - por muitos outros programas , (! Por exemplo, Ruby, Perl, e até mesmo próprio PowerShell da Microsoft ()) , mas Seu uso não é SAFE :

    • \" é o que muitos executáveis ??e intérpretes seja requerem - incluindo o próprio PowerShell da Microsoft quando seqüências passadas do lado de fora - ou, no caso de compiladores da Microsoft, apoio como uma alternativa para "" -., em última análise, porém, é até o programa de metas para analisar a lista de argumentos
      • Exemplo: foo.exe "We had 3\" of rain."
    • Entretanto, o uso \" PODE RESULTAR EM indesejada, execução arbitrária de comandos de e / ou redirecionamentos de entrada / saída :
      • Os seguintes caracteres apresentar esse risco: & | < >
      • Por exemplo, os seguintes resultados em execução não intencional do comando ver; veja mais abaixo para uma explicação e o próximo ponto de bala para uma solução alternativa:
        • foo.exe "3\" of snow" "& ver."
    • Para PowerShell em Windows , \"" e "^"" são robustos, mas as alternativas limitadas (veja a seção "Chamando CLI do PowerShell ..." abaixo ).
  • Se você deve usar \", existem apenas 3 segura se aproxima , que são, no entanto bastante complicado : ponta do chapéu para TS por sua ajuda.

    • Usar (possivelmente seletiva ) atrasou a expansão de variáveis ?? em seu arquivo de lote, você pode loja literal \" em um variável e referência essa variável dentro de uma string "..." usando !var! sintaxe - veja T S resposta útil .

      • A abordagem acima, apesar de ser complicado, tem a vantagem de que você pode aplicá-lo metodicamente e que funciona robustamente , com qualquer entrada.
    • Apenas com strings literais - aqueles que não envolvem variáveis ??- você começa uma abordagem semelhante metódica: categoricamente ^-escape todas metacharacters cmd.exe: " & | < > e - se você também deseja suprimir a expansão de variáveis ??- %:
      foo.exe ^"3\^" of snow^" ^"^& ver.^"

    • Caso contrário, você deve formular sua seqüência baseada no reconhecimento de que partes do cmd.exe corda considera unquoted , devido à má interpretação \" como o fechamento de delimitadores:

      • em literal porções contendo metacaracteres shell: ^-escapar deles; usando o exemplo acima, é & que deve ser escapou-^:
        foo.exe "3\" of snow" "^& ver."

      • em porções com referências de variáveis ??de estilo %...% : garantir que cmd.exe os considera parte de uma cadeia "..." e que que os valores das variáveis ??não-se ter incorporado , citações desequilibradas -. que nem sempre é possível

Para obter informações básicas, continue a ler.


Fundo

Nota: Este é baseado em minhas próprias experiências. Do deixe-me saber se eu estiver errado.

POSIX-como conchas, como Bash em Unix-like sistemas tokenizar a lista de argumentos (string) antes de passar argumentos individualmente para o programa alvo: entre outras expansões, eles dividir a lista de argumentos em palavras individuais (repartição de palavras) e caracteres remove citando as palavras resultantes (remoção citação). O programa de destino é entregue um array de argumentos individuais , com sintática citações removido .

Por outro lado, o interpretador de comandos do Windows, aparentemente, não tokenizar a lista de argumentos e simplesmente passa o única string compreendendo todas argumentos - incluindo caracteres citando. -. Para o programa de destino
No entanto, alguns pré-processamento ocorre antes da seqüência única é passado para o programa de destino: caracteres ^ fuga. fora de cadeias duplas-citado são removidos (escapam a seguinte carvão animal.), e referências de variáveis ??(por exemplo, %USERNAME%) são interpolado em primeiro lugar.

Assim, ao contrário, em Unix, é responsabilidade do programa de metas para análise para analisar a cadeia de argumentos e dividi-la em argumentos individuais com citações retiradas. Assim, programas diferentes podem hipoteticamente requerem diferentes métodos que escapam e não há nenhum único mecanismo de fuga que é garantida para trabalhar com todos os programas - < a href = "https://stackoverflow.com/a/4094897/45375"> https://stackoverflow.com/a/4094897/45375 contém excelente fundo sobre a anarquia que é o Windows de linha de comando de análise.

Na prática, \" é muito comum, mas não SAFE , como mencionado acima:

Desde si cmd.exe não reconhece \" como um escapou de aspas duplas, ele pode interpretar mal depois fichas na linha de comando como unquoted e, potencialmente, interpretá-los como comandos e / ou redirecionamentos de entrada / saída .
Em poucas palavras: o problema à tona, se qualquer um dos seguintes caracteres seguir um abertura ou desequilibrada \": & | < > ; por exemplo:

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

cmd.exe vê os seguintes tokens, resultante da interpretação incorreta\" como um double-quote regulares:

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

Desde cmd.exe pensa que & ver. é não cotadas , ele interpreta como & (o operador-seqüenciamento de comando), seguido do nome de um comando a ser executado (ver. - o . é ignorado; relatórios ver informações sobre a versão do cmd.exe).
O efeito geral é:

  • Em primeiro lugar, foo.exe é invocado com o primeiro 3 fichas somente.
  • Em seguida, ver comando é executado.

Mesmo nos casos em que o comando acidental não faz nenhum dano, o comando geral não funcionará como projetado, dado que nem todos os argumentos são passados ??a ele.

Muitos compiladores / intérpretes reconhecer apenas \" - por exemplo, o compilador GNU C / C ++, Python, Perl, Ruby, mesmo própria PowerShell da Microsoft quando chamado a partir cmd.exe - e, exceto para PowerShell com \"", para eles não há uma solução simples para esse problema.
Essencialmente, você tem que saber com antecedência quais partes de sua linha de comando são mal interpretados como não indicada, e seletivamente ^-escapar todas as instâncias do & | < > naquelas partes.

Por outro lado, uso de "" é SAFE , mas é lamentavelmente suportado apenas por executáveis ??baseados em Microsoft-compilador e arquivos em lote (no caso de arquivos em lote, com as peculiaridades discutido acima), que exclui notáveis ?? PowerShell -. Veja a próxima seção


Chamando CLI do PowerShell de cmd.exe ou POSIX-como conchas:

Nota: Consulte a seção inferior de como citando é tratado dentro PowerShell

.

PowerShell , quando chamado a partir do exterior - por exemplo, de cmd.exe, seja a partir da linha de comando ou um arquivo de lote - reconhece única \" e, no Windows também """ eo \"" mais robusto / "^"" (mesmo que internamente PowerShell usa ` como o caractere de escape em strings com aspas duplas e também aceita "" - ver bottom seção):

Em Windows , chamando a partir cmd.exe / um arquivo de lote:

  • "" quebras , porque é fundamentalmente suportada:

    • powershell -c " ""ab c"".length " -> erro "A cadeia está faltando o terminator"
  • \" e """ trabalho , em princípio, , mas não são segura :

    • powershell -c " \"ab c\".length " funciona como pretendido: que saídas 5 (note o 2 espaços)
    • Mas não é seguro, porque metacharacters cmd.exe quebrar o comando, a menos que escapou:
      powershell -c " \"a& c\".length " quebras , devido à &, que teria que ser escapado como ^&
  • \"" é segura , mas espaços em branco normalize interior , que pode ser indesejado:

    • powershell -c " \""a& c\"".length " saídas 4 (!), Porque as 2 vagas são normalizadas para 1.
  • "^"" é a melhor escolha para Windows PowerShell , especificamente , onde é seguro e de preservação de espaços em branco, mas com o PowerShell Núcleo (no Windows) é o mesmo que \"" , ou seja, whitespace- normalizando . O crédito vai para Venryx para descobrir esta abordagem.

    • powershell -c " "^""a& c"^"".length " funciona :. não quebrar - apesar & - e saídas 5, ou seja, espaços em branco corretamente preservado

    • PowerShell Núcleo : pwsh -c " "^""a& c"^"".length " funciona , mas 4 saídas, ou seja, normaliza espaço em branco , como \"" faz

      <. / li>

Em Unix-like plataformas (Linux, MacOS), chamando PowerShell Núcleo 's CLI, pwsh de um POSIX-como shell tais como bash:

Você deve uso \" , que, no entanto, é segura e de preservação de espaços em branco :

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

Informação relacionada

  • ^ só pode ser usado como o caractere de escape no unquoted cordas -. Dentro de strings com aspas duplas, ^ não é especial e tratado como um literal

    • CAVEAT : Uso de ^ em parâmetros passados ??para a declaração call está quebrado (isso se aplica a ambos os usos de call: invocando outro arquivo batch ou binário, e chamar um sub-rotina no mesmo arquivo batch):
      • casos ^ em entre aspas valores são inexplicavelmente dobrou , alterando o valor sendo passado: por exemplo, se %v% variável contém a^b valor literal , cessionários call :foo "%v%" "a^^b" (!) para %1 (o primeiro parâmetro) em :foo sub-rotina.
      • Não cotados uso de ^ com call é quebrado por completo em que ^ não pode mais ser usado para escapar caracteres especiais : por exemplo, call foo.cmd a^&b silêncio breaks (em vez de passar a&b literal demais foo.cmd, como seria o caso sem call) - (!). foo.cmd nunca é sequer invocado, pelo menos no Windows 7
  • Escapando uma % literal é um caso especial , infelizmente, que requer sintaxe distinta, dependendo se uma string é especificada no linha de comando vs . dentro de um arquivo de lote ; consulte https://stackoverflow.com/a/31420292/45375

    • A curto do que: Dentro de um arquivo de lote, o uso %%. Na linha de comando, % não se pode escapar, mas se você colocar uma ^ no início, fim ou dentro de um nome de variável em um unquoted string (por exemplo, echo %^foo%), você pode evitar a expansão de variáveis ??( interpolação); instâncias % na linha de comando, que não fazem parte de uma referência variável são tratados como literais (por exemplo, 100%).
  • Geralmente, para trabalhar com segurança com valores variáveis ??que podem conter espaços e caracteres especiais :

    • Atribuição : Anexar ambos o nome da variável eo valor em um única par de aspas duplas ; por exemplo, atribui set "v=a & b" valor a & b literal para %v% variável (por contraste, set v="a & b" faria parte-aspas do valor). Escapar casos % literais como %% (funciona apenas em arquivos em lote - ver acima)
    • .
    • Referência : aspas variáveis ??referências para se certificar de que seu valor não é interpolada; por exemplo, echo "%v%" não sujeitar o valor de %v% para interpolação e impressões "a & b" (mas nota que as aspas duplas são invariavelmente impresso também). Em contraste, echo %v% passa a literal para echo, interpreta & como o operador-seqüenciamento de comando, e, portanto, tenta executar um comando chamado b.
      Observe também a ressalva acima re uso de ^ com a declaração call.
    • Externo programas normalmente cuidar da remoção colocando aspas duplas em torno de parâmetros, mas, como foi observado, em arquivos em lote você tem que fazê-lo sozinho (por exemplo, %~1 para remover colocando aspas duplas do 1º parâmetro) e, infelizmente, não há nenhuma maneira direta que eu conheço para obter echo para imprimir um valor variável fielmente sem os que encerram aspas .
      • ofertas Neil uma solução baseada em for que as obras , desde que o valor não tem incorporado aspas duplas ; g .:
        set "var=^&')|;,%!" for /f "delims=" %%v in ("%var%") do echo %%~v
  • cmd.exe não reconhecer única -quotes como delimitadores de cordas - eles são tratados como literais e não pode geralmente ser usado para delimitar cordas com espaços em branco incorporado; Além disso, segue-se que os sinais que encostam as aspas simples e quaisquer tokens entre são tratados como não indicada por cmd.exe e interpretado em conformidade.

    • No entanto, dado que os programas alvo em última análise, realizar sua própria análise argumento, alguns programas como Ruby reconhecem cordas individuais citada mesmo no Windows; pelo contrário, executáveis ??C / C ++, Perl e Python fazer não reconhecê-los.
      Mesmo se suportado pelo programa de destino, no entanto, não é aconselhável a utilização de cordas individuais citadas, dado que o seu conteúdo não são protegidos de interpretação potencialmente indesejados por cmd.exe.

Citando em PowerShell:

Windows PowerShell é uma casca muito mais avançado do que cmd.exe, e tem sido uma parte do Windows há muitos anos (e PowerShell Núcleo trouxe a experiência PowerShell para MacOS e Linux também).

PowerShell funciona de forma consistente internamente em relação ao citar:

  • dentro de strings com aspas duplas, o uso `" ou "" para escapar aspas
  • dentro de strings de aspas simples, o uso '' para escapar aspas simples

Isso funciona na linha de comando PowerShell e quando passar parâmetros para scripts do PowerShell ou funções de em PowerShell.

(Como discutido acima, passando uma escaparam aspas para PowerShell do lado de fora requer \" ou, mais robusta, \"" - nada mais funciona).

Infelizmente, ao invocar externo programas de PowerShell, você se depara com a necessidade de ambos acomodar próprias regras citando do PowerShell e para escapar para o destino programa:

Este comportamento problemático também é discutido e resumidos na esta questão docs GitHub

duplo -quotes dentro duplo -quoted cordas :

Considere "3`" of rain" string, que PowerShell-internamente traduz em 3" of rain literal.

Se você quer passar esta cadeia para um programa externo, você tem que aplicar o programa do alvo escapar além para o PowerShell ; dizer que você quer passar a corda para um programa C, que espera incorporado aspas para ser escapado como \":

foo.exe "3\`" of rain"

Observe como ambos `" - para fazer PowerShell feliz - e o \ - para tornar o feliz programa de metas - devem estar presentes.

A mesma lógica aplica-se a invocar um arquivo de lote, onde "" deve ser utilizado:

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

Por outro lado, a incorporação de única -quotes em um duplo string -quoted requer nenhum escapar a todos.

Single -quotes dentro única -quoted cordas do não requerem adicional escapando; considerar '2'' of snow', que é a representação PowerShell' de 2' of snow.

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

PowerShell traduz cordas individuais citado para aqueles com aspas duplas antes de passá-los para o programa de destino.

No entanto, duplo -quotes dentro única -quoted cordas , que não precisa escapar para PowerShell , que ainda precisa ser escapado para o programa de destino :

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

PowerShell v3 introduziu a magia opção --% , o chamado símbolo de análise de parada , que alivia um pouco a dor, passando nada depois it uninterpreted para o programa de destino, exceto por referências de estilo cmd.exe ambiente variável (por exemplo, %USERNAME%), que são expandido; por exemplo:.

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

Observe como escapar da " incorporado como \" para o programa de destino única (e não também para PowerShell como \`") é suficiente.

No entanto, esta abordagem:

  • não permite escape caracteres %, a fim de expansões ambiente variável a evitar.
  • se opõe direto uso de variáveis ??e expressões PowerShell; em vez disso, a linha de comando deve ser construído em uma variável de cadeia, numa primeira fase, e, em seguida, invocado com Invoke-Expression em um segundo.

Assim, apesar de seus muitos avanços, PowerShell não tem feito muito mais fácil escapar ao chamar programas externos. Ele tem, no entanto, introduziu suporte para strings de aspas simples.

Eu me pergunto se é fundamentalmente possível no mundo do Windows para alternar nunca para o modelo Unix de deixar o shell fazer todo o tokenization e cotação de remoção previsivelmente , na frente , , independentemente do programa de destino , e depois invocar o programa de destino, passando os tokens resultantes.

Como um complemento para de mklement0 excelente resposta :

Quase todos os executáveis ??aceitar \" como um " escapou. uso seguro no cmd, porém, é quase só é possível usando DELAYEDEXPANSION.
Para enviar explicitamente uma " literal a algum processo, \" atribuir a uma variável de ambiente e, em seguida, usar essa variável, sempre que você precisa para passar uma cotação. Exemplo:

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

Nota SETLOCAL ENABLEDELAYEDEXPANSION parece funcionar somente dentro de arquivos em lote. Para obter DELAYEDEXPANSION em uma sessão interativa, começar cmd /V:ON.

Se o seu batchfile trabalho does't com DELAYEDEXPANSION, você pode habilitá-lo temporariamente:

::region without DELAYEDEXPANSION

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

::region without DELAYEDEXPANSION

Se você quer passar o conteúdo dinâmico a partir de uma variável que contém citações que são escapou, como "" você pode substituir "" com \" em expansão:

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

Esta substituição não é seguro com a expansão estilo %...%!

Em caso de bash -c "g++-linux-4.1 !v_params:"=\"!" é a versão segura.


Se, por alguma razão ainda DELAYEDEXPANSION permitindo temporariamente não é uma opção, continue a ler:

Usando \" de dentro cmd é um pouco mais seguro se a gente sempre precisa escapar caracteres especiais, em vez de apenas algumas vezes. (É menos provável que se esqueça um acento circunflexo, se é consistente ...)

Para conseguir isso, um precede qualquer citação com um acento circunflexo (^"), cita que deve atingir o processo filho como literais deve adicionalmente ser precedidos por uma reação (\^"). todas caracteres meta casca devem ser precedidos por ^, bem como, por exemplo, & => ^&; | => ^|; > => ^>; etc.

Exemplo:

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

Fonte: citações Todos comandar argumentos de linha da maneira errada , consulte 'a melhor método de citar'


Para passar o conteúdo dinâmico, é preciso garantir o seguinte:
A parte do comando que contém a variável deve ser considerado "citado" por cmd.exe (Isso é impossível se a variável pode conter citações - não escrever %var:""=\"% ). Para conseguir isso, o último " antes da variável eo primeiro " após a variável não são escapou-^. CMD-metacharacters entre aqueles dois " não deve ser escapado. Exemplo:

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

Isto não é seguro, se %dynamic_content% pode conter citações incomparáveis.

Por exemplo, para Unreal ferramenta run Automation motor de arquivo de lote - isso funcionou para mim

por exemplo: -cmdline = "-Serviço de mensagens" -device = dispositivo -addcmdline = "- sessionId = Sessão -SessionOwner = 'proprietário' -SessionName = 'construir' -dataProviderMode = -LogCmds locais = 'LogCommodity OFF' -execcmds = 'Lista de automação; runtests testes separados + + + por T1 + T2; sair' "-run

Espero que isso ajude alguém, trabalhou para mim.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top