Разбор аргументов cmdline, содержащих = - PullRequest
9 голосов
/ 30 августа 2011

После многих лет использования пакетных файлов я с удивлением обнаружил, что знак равенства '=' считается разделителем аргументов.

Данный тестовый скрипт:

echo arg1: %1
echo arg2: %2
echo arg3: %3

и вызов:

test.bat a=b c

вывод:

arg1: a
arg2: b
arg3: c

Почему это так и как этого можно избежать? Я не хочу, чтобы пользователь скрипта учел эту причуду и процитировал «a = b», что нелогично.

Этот пакетный скрипт был запущен в Windows 7.

===== РЕДАКТИРОВАТЬ =====

Немного больше предыстории: я столкнулся с этой проблемой при написании файла bat для запуска приложения Java. Я хотел использовать некоторые аргументы в файле bat, а затем передать остальное в Java-приложение. Поэтому моей первой попыткой было сделать shift, а затем перестроить список аргументов (так как shift не затрагивается *1020*). Это выглядело примерно так, и вот когда я обнаружил проблему:

rem Rebuild the args, %* does not work after shift
:args
if not "%1" == "" (
  set ARGS=!ARGS! %1
  shift
  goto args
)

Следующим шагом было больше не использовать сдвиг, а реализовать сдвиг вручную, удаляя по одному символу за раз из %*, пока не встретится пробел:

rem Remove the 1st arg if it was the profile
set ARGS=%*
if not "%FIRST_ARG%" == "%KNOA_PROFILE%" goto remove_first_done
:remove_first
if not defined ARGS goto remove_first_done
if "%ARGS:~0,1%" == " " goto remove_first_done
set ARGS=%ARGS:~1%
goto remove_first
:remove_first_done

Но это уродливо и может все же потерпеть неудачу в некоторых случаях, которые я не рассматривал Итак, в конце концов я решил написать программу на Java для разбора аргументов! В моем случае это нормально, так как я запускаю сервер и штраф за дополнительный вызов Java минимален. Это ошеломляет то, что ты иногда делаешь.

Вы можете спросить, почему я не позаботился об аргументах в самом приложении Java? Ответ в том, что я хочу иметь возможность передавать параметры JVM, такие как -Xmx, которые должны быть обработаны перед вызовом java.

Ответы [ 5 ]

6 голосов
/ 31 августа 2011

Полагаю, это так, что /param=data совпадает с /param data

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

@echo off
setlocal ENABLEEXTENSIONS
set param=1
:fixnextparam
set p=
((echo "%~1"|find " ")>nul)||(
    call :fixparam %param% "%~1" "%~2" %* 2>nul
)
if "%p%"=="" (set "p%param%=%1") else shift
shift&set /A param=%param% + 1
if not "%~1"=="" goto fixnextparam

echo.1=%p1%
echo.2=%p2%
echo.3=%p3%
echo.4=%p4%
echo.5=%p5%
goto:EOF


:fixparam
set p%1=
for /F "tokens=4" %%A in ("%*") do (
    if "%%~A"=="%~2=%~3" set p=!&set "p%1=%%A"
)
goto:EOF

Когда я выполняю test.cmd foo=bar baz "fizz buzz" w00t, я получаю:

1=foo=bar
2=baz
3="fizz buzz"
4=w00t
5=

Проблема в этом, конечно, в том, что вы не можете выполнять расширение переменных в стиле% ~ dp1. Невозможно выполнить call :mylabel %* и затем использовать% 1, так как call: batchlabel имеет ту же проблему разбора параметров!

Если вам действительно нужна обработка% ~ dp1, вы можете использовать WSH / пакетный гибрид hack:

@if (1==1) @if(1==0) @ELSE
@echo off
@SETLOCAL ENABLEEXTENSIONS
if "%SPECIALPARSE%"=="*%~f0" (
    echo.1=%~1
    echo.2=%~2
    echo.3=%~3
    echo.4=%~4
    echo.5=%~5
) else (
    set "SPECIALPARSE=*%~f0"
    cscript //E:JScript //nologo "%~f0" %*
)
@goto :EOF
@end @ELSE
w=WScript,wa=w.Arguments,al=wa.length,Sh=w.CreateObject("WScript.Shell"),p="";
for(i=0;i<al;++i)p+="\""+wa.Item(i)+"\" ";
function PipeStream(i,o){for(;!i.AtEndOfStream;)o.Write(i.Read(1))}
function Exec(cmd,e){
    try{
        e=Sh.Exec(cmd);
        while(e.Status==0){
            w.Sleep(99);
            PipeStream(e.StdOut,w.StdOut);
            PipeStream(e.StdErr,w.StdErr);
        }
        return e.ExitCode;
    }catch(e){return e.number;}
}
w.Quit(Exec("\""+WScript.ScriptFullName+"\" "+p));
@end
2 голосов
/ 31 августа 2011
@echo off
setlocal enabledelayedexpansion

if %1 neq ~ (
 set "n=%*"
 for %%a in ("!n: =" "!") do (
 set "s=%%a"
 if !s:~0^,2!==^"^" (
   set "s=!s:" "= !"
   set "s=!s:""="!"
)
 set "m=!m! !s!"
 )
 %0 ~ !m!
)
endlocal
shift

echo arg1: %~1
echo arg1: %~2
echo arg1: %~dp3
exit /b

c:> untested.bat a=b c "%USERPROFILE%"
2 голосов
/ 31 августа 2011

Я только отвечаю на это: >> Почему это так и как этого избежать?

Мое предложение: использовать лучший язык. Нет, я не шучу. пакет имеет слишком много причуд / нюансов, таких как это, а также множество других ограничений, просто не стоит тратить время на уродливые / неэффективные обходные пути. Если вы работаете в Windows 7 и выше, почему бы не попробовать использовать VBScript или даже PowerShell. Эти инструменты / язык очень помогут в ваших ежедневных задачах программирования / администрирования. В качестве примера того, как vbscript может позаботиться о такой проблеме:

For i=0 To WScript.Arguments.Count-1
    WScript.Echo WScript.Arguments(i)
Next

Выход:

C:\test>cscript //nologo myscript.vbs a=b c
a=b
c

Обратите внимание, что он правильно обрабатывает аргументы.

1 голос
/ 05 сентября 2011

@ jeb: здесь другой метод

untested.cmd

@echo off
setlocal enabledelayedexpansion

set "param=%*"
set param="%param: =" "%"

for /f "delims=" %%a in ('echo %param: =^&echo.%') do (
  set "str=%%a"
  if !str:~0^,2!==^"^" (
     set "str=!str:^&echo.=!"
     set "str=!str:"^"= !"
     set str="!str:~1,-1!"
  )
  set "m=!m! !str!"
)

Call :sub %m%
endlocal & goto :eof

:sub
 echo arg1: %~1
 echo arg2: %~2
 echo arg3: %~3
 echo arg4: %~4
goto :eof
0 голосов
/ 22 мая 2015

Опять же, я не могу объяснить неожиданное поведение, но есть очень простое решение. Просто измените ваши ссылки на аргументы, а затем приведите их в кавычки:

test.bat скрипт:

echo arg1: %~1
echo arg2: %~2
echo arg3: %~3

Вызывать:

test.bat "a=b" c

Выход:

arg1: a=b
arg2: c
arg3:

Обратите внимание, что ссылка на аргументы тильдой (~) удаляет начальные / конечные кавычки из аргумента.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...