2010-11-17 23 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 

下列情況將立即終止程序:

  • 沒有參數發現
  • 多參數
  • 空參數(""",或"允許在參數值

爲了緩解這些限制的最後一個參數)

  • 一個或一個以上報價("),只需註釋掉相關線路。閱讀內嵌評論以獲取更多信息。不要試圖關閉多線參數陷阱!