2010-11-17 11 views
11

come discusso in un'altra thread How to avoid cmd.exe interpreting shell special characters like < > ^ non è facile ottenere tutti i parametri dalla riga di comando.Come ricevere anche i più strani parametri della riga di comando?

Un semplice

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

non sono sufficienti, se si dispone di una richiesta come

myBatch.bat abc"&"^&def 

ho una soluzione, ma ha bisogno di un file temporaneo, ed è, inoltre, non a prova di proiettile.

@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!' 

non riesce con qualcosa come myBatch.bat% un, esso esposizione non il % un

in questa situazione una semplice echo% 1 avrebbe funzionato.
Ovviamente è il ciclo for, ma non so come cambiarlo.
Forse esiste un'altra soluzione semplice.

Non ho bisogno di questo per risolvere un problema reale, ma mi piacciono le soluzioni che sono a prova di proiettile in ogni situazione, non solo nella maggior parte dei casi.

risposta

7

Io non credo che nessuno ha trovato tutti i fori in questo, tranne che per l'incapacità di leggere a capo nei parametri:

@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 

Quanto sopra viene da una vivace discussione DosTips - http://www.dostips.com/forum/viewtopic.php?p=13002#p13002. L'utente di DosTips Liviu ha inventato il pezzo critico SETLOCAL DisableExtensions.

0

Spetta all'utente che digita il comando di uscire da qualsiasi carattere speciale. Il tuo programma non può fare nulla su ciò che fa la shell prima che il tuo programma sia eseguito. Non c'è altra soluzione "a prova di proiettile" a questo.

+0

Questo punto è chiaro, è ovvio che abc "&"^& def verranno tradotti in abc "&" & def, ma ancora non può essere gestito con un semplice set "var =% ~ 1" – jeb

+3

L'utente avrebbe quindi bisogno di anticipare quante volte l'argomento è usato nel file batch per aggiungere il giusto livello di escape ad esso. Non è abbastanza usabile, immagino ;-) – Joey

1

Il codice qui sotto si basa sulla vagante Foolproof Counting of Arguments argomento su DosTips e this answer da 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 [email protected] 
    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 

Le seguenti condizioni risolvere immediatamente il programma:

  • parametri trovato
  • multilinea parametro
  • parametro vuoto (.210, o " è consentito per l'ultimo parametro)
  • uno o più citazioni (") in un valore di parametro

Per facilitare queste restrizioni, è sufficiente commentare le righe rilevanti. Leggi i commenti in linea per maggiori informazioni. Non tentare di disattivare la trappola dei parametri multilinea!

Problemi correlati