Como receber até mesmo os parâmetros de linha de comando mais estranhos?

como discutido em outro tópico Como evitar o cmd.exe interpretando caracteres especiais do shell como ^ não é fácil obter todos os parâmetros da linha de comando.

Um simples

set var=%1 set "var=%~1" 

não são suficientes, se você tiver um pedido como

 myBatch.bat abc"&"^&def 

Eu tenho uma solução, mas ela precisa de um arquivo temporário e também não é uma prova de bala.

 @echo off setlocal DisableDelayedExpansion set "prompt=X" ( @echo on for %%a in (4) do ( rem #%1# ) ) > XY.txt @echo off for /F "delims=" %%a in (xy.txt) DO ( set "param=%%a" ) setlocal EnableDelayedExpansion set param=!param:~7,-4! echo param='!param!' 

Ele falha com algo como myBatch.bat% a , ele exibe 4 não o % a

nessa situação, um eco simples % 1 funcionaria.
É obviamente o loop, mas não sei como mudar isso.
Talvez exista outra solução simples.

Eu não preciso disso para resolver um problema real, mas gosto de soluções que sejam à prova de balas em cada situação, não apenas na maioria dos casos.

Eu não acho que alguém tenha encontrado algum buraco nisso, exceto pela incapacidade de ler novas linhas nos parâmetros:

 @echo off setlocal enableDelayedExpansion set argCnt=1 :getArgs >"%temp%\getArg.txt" < "%temp%\getArg.txt" ( setlocal disableExtensions set prompt=# echo on for %%a in (%%a) do rem . %1. echo off endlocal set /p "arg%argCnt%=" set /p "arg%argCnt%=" set "arg%argCnt%=!arg%argCnt%:~7,-2!" if defined arg%argCnt% ( set /a argCnt+=1 shift /1 goto :getArgs ) else set /a argCnt-=1 ) del "%temp%\getArg.txt" set arg 

O texto acima vem de uma discussão animada sobre o DosTips - http://www.dostips.com/forum/viewtopic.php?p=13002#p13002 . O usuário do DosTips, Liviu, apresentou a peça crítica do SETLOCAL DisableExtensions .

O código abaixo é baseado no tópico de Contagem de Argumentos Difusos de DosTips e esta resposta por jeb :

 @echo off & setLocal enableExtensions disableDelayedExpansion (call;) %= sets errorLevel to 0 =% :: initialise variables set "paramC=0" & set "pFile=%tmp%\param.tmp" :loop - the main loop :: inc param counter and reset var storing nth param set /a paramC+=1 & set "pN=" :: ECHO is turned on, %1 is expanded inside REM, GOTO jumps over REM, :: and the output is redirected to param file for %%A in (%%A) do ( setLocal disableExtensions set prompt=@ echo on for %%B in (%%B) do ( @goto skip rem # %1 # ) %= for B =% :skip - do not re-use this label @echo off endLocal ) >"%pFile%" %= for A =% :: count lines in param file for /f %%A in (' find /c /v "" ^< "%pFile%" ') do if %%A neq 5 ( >&2 echo(multiline parameter values not supported & goto die ) %= if =% :: extract and trim param value for /f "useBack skip=3 delims=" %%A in ("%pFile%") do ( if not defined pN set "pN=%%A" ) %= for /f =% set "pN=%pN:~7,-3%" :: die if param value is " or "", else trim leading/trailing quotes if defined pN ( setLocal enableDelayedExpansion (call) %= OR emulation =% if !pN!==^" (call;) if !pN!=="" (call;) if errorLevel 1 ( for /f delims^=^ eol^= %%A in ("!pN!") do ( endLocal & set "pN=%%~A" ) %= for /f =% ) else ( >&2 echo(empty parameter values (""^) not supported & goto die ) %= if errorLevel =% ) else ( :: no more params on cmd line set /a paramC-=1 & goto last ) %= if defined =% :: die if param value contains " if not "%pN:"=""%"=="%pN:"=%" ( >&2 echo(quotes (^"^) in parameter values not supported & goto die ) %= if =% :: assign nth param, shift params, and return to start of loop set "param%paramC%=%pN%" & shift /1 & goto loop :last - reached end of params :: no param values on cmd line if %paramC% equ 0 ( >&2 echo(no parameter values found & goto die ) %= if =% :: list params set param goto end :die (call) %= sets errorLevel to 1 =% :end :: exit with appropriate errorLevel endLocal & goto :EOF 

As seguintes condições terminarão o programa imediatamente:

  • nenhum parâmetro encontrado
  • parâmetro multilinha
  • parâmetro vazio ( """ ou " é permitido para o último parâmetro)
  • uma ou mais aspas ( " ) em um valor de parâmetro

Para aliviar essas restrições, simplesmente comente as linhas relevantes. Leia os comentários em linha para mais informações. Não tente desligar o trap de parâmetro de múltiplas linhas!

Cabe ao usuário digitar o comando para escaping de qualquer caractere especial. Seu programa não pode fazer nada sobre o que o shell faz antes que seu programa seja executado. Não há outra solução “à prova de balas” para isso.