2010-11-17 22 views
11

在其他线程中讨论How to avoid cmd.exe interpreting shell special characters like < > ^ 从命令行获取所有参数并不容易。如何接收最奇怪的命令行参数?

简单

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

是不够的,如果你有一个像

myBatch.bat abc"&"^&def 

我有一个解决方案的要求,但它需要一个临时文件,而且这也不是防弹。

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

它失败的东西,如myBatch.bat%一,它显示没有%在这种情况

简单回声%1会工作。
这显然是for循环,但我不知道如何改变这一点。
也许存在另一个简单的解决方案。

我不需要这个来解决实际问题,但我喜欢在每种情况下都是防弹的解决方案,而不是在大多数情况下。

回答

7

我不认为任何人发现任何漏洞在此,除了不能在参数读取换行符:

@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 

以上来自一个热闹DosTips讨论 - http://www.dostips.com/forum/viewtopic.php?p=13002#p13002。 DosTips用户Liviu想出了关键的SETLOCAL DisableExtensions作品。

0

这是由用户输入命令来转义任何特殊字符。你的程序在你的程序运行之前不能做任何有关shell的工作。对此,没有其他“防弹”解决方案。

+0

这一点很清楚,很明显abc“&”^&def将被转换为abc“&”&def,但仍然无法用简单的set“var =%〜1”来处理。 – jeb 2010-11-17 07:18:02

+3

用户然后需要预测在批处理文件中使用了多少次参数来为其添加适当的转义级别。这不是很有用,我想;-) – Joey 2010-11-18 13:01:49

1

下面的代码是由jeb基于DosTipsthis answer海北Foolproof Counting of Arguments话题:

@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 

下列情况将立即终止程序:

  • 没有参数发现
  • 多参数
  • 空参数(""",或"允许在参数值

为了缓解这些限制的最后一个参数)

  • 一个或一个以上报价("),只需注释掉相关线路。阅读内嵌评论以获取更多信息。不要试图关闭多线参数陷阱!