Как получить даже самые странные параметры командной строки? - PullRequest
15 голосов
/ 17 ноября 2010

как обсуждалось в другом потоке Как избежать cmd.exe, интерпретирующего специальные символы оболочки, такие как <> ^ , нелегко получить все параметры из командной строки.

Простой

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% a , отображается 4 , а не % a

вв этой ситуации простой echo% 1 будет работать.
Это, очевидно, цикл for, но я не знаю, как это изменить.
Возможно, существует другое простое решение.

Мне это не нужно для решения реальной проблемы, но мне нравятся решения, которые являются пуленепробиваемыми в каждой ситуации, а не только в большинстве случаев.

Ответы [ 4 ]

9 голосов
/ 26 марта 2012

Я не думаю, что кто-то обнаружил в этом какие-либо дыры, за исключением невозможности прочитать новые строки в параметрах:

@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, Ливиу, придумал критический кусок SETLOCAL DisableExtensions.

1 голос
/ 15 апреля 2019

Я изобрел синтаксическая ошибка-техника , чтобы решить проблему (частично).

С этим решением можно даже получить многострочные параметры, а также символы возврата каретки.
Не существует известного параметра, который не работает!

НО недостаток этого решения, основной процесс завершается, и продолжается только дочерний процесс.
Это является следствием уловки захвата,Синтаксическая ошибка создается с помощью недопустимого блока скобок ( Prepare ) PARAMS....
Но сама синтаксическая ошибка выводит полный блок, включая расширенное значение %*.
Вывод перенаправляется в файл с помощью permanent redirect technic.
И дочерний процесс может извлечь полный параметр из файла.

Это решение может быть полезно, когда пакетный файл обрабатывает только параметр и всегда завершается впоследствии.

@echo off
REM *** Thread redirector 
for /F "tokens=3 delims=:" %%F in ("%~0") do goto %%F

REM *** Clear params.tmp
break > params.tmp

start "" /b cmd /k "%~d0\:StayAlive:\..\%~pnx0 params.tmp"

(set LF=^
%=empty=%
)
REM *** Change prompt for better recognition
prompt #PROMPT#


REM *** Change streams permanently
REM *** stream1 redirects to params.tmp
REM *** stream2 redirects to nul
echo on >nul 2>nul 0>nul 3>params.tmp 4>nul 5>&3

@REM *** This is the magic part, it forces a syntax error, the error message itself shows the expanded %asterix without ANY modification
( Prepare ) PARAMS:%LF%%*%LF%

echo Works
exit /b


REM *** Second thread to fetch and show the parameters
:StayAlive

:__WaitForParams
if %~z1 EQU 0 (
    goto :__WaitForParams
)
REM *** Show the result
findstr /n "^" %1 
1 голос
/ 04 февраля 2018

Код ниже основан на бессвязном надежном подсчете аргументов тема DosTips и этот ответ 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

Следующие условия немедленно прервут программу:

  • параметры не найдены
  • многострочный параметр
  • пустой параметр (""" или" разрешено для последнего параметра)
  • одна или несколько кавычек (") в значении параметра

Чтобы ослабить эти ограничения, просто закомментируйте соответствующие строки.Прочитайте встроенные комментарии для получения дополнительной информации.Не пытайтесь отключить многострочное прерывание параметра!

0 голосов
/ 17 ноября 2010

Пользователь, который вводит команду, должен экранировать любые специальные символы.Ваша программа не может ничего сделать с тем, что делает оболочка, прежде чем ваша программа даже запустится.Для этого нет другого «пуленепробиваемого» решения.

...