Давайте сначала посмотрим на mysample.bat
, содержащий только
@echo off
for %%I in (%*) do echo %%I
и что выводится при запуске в окне командной строки в каталоге, содержащем mysample.bat
командную строку:
mysample.bat -p1=1 -p2=2 -p3="abc" myfile
Вывод:
-p1
1
-p2
2
-p3
"abc"
myfile
Таким образом, знак равенства интерпретируется FOR как разделитель аргументов, такой как пробел или запятая и некоторые другие символы.
Таким образом, простое решение получить последний аргумент, назначенный переменной среды после проверки кода, если пакетный файл был вызван хотя бы с одним аргументом:
set "FileName="
for %%I in (%*) do set "FileName=%%~I"
if defined FileName echo File name is: %FileName%
Вывод: File name is: myfile
Но как насчет вызова командного файла с:
mysample.bat -p1=1 myfile -p2=2 -p3="abc"
Что ж, неудивительно, что вывод неправильный с: File name is: abc
Как насчет использованиякоманда SHIFT ?
@echo off
set "ArgNumber=1"
:ArgLoop
if "%~1" == "" goto :EOF
echo Argument %ArgNumber% is: "%~1"
set /A ArgNumber+=1
shift
goto ArgLoop
Вывод при запуске пакетного файла с приведенным выше списком аргументов:
Argument 1 is: "-p1"
Argument 2 is: "1"
Argument 3 is: "myfile"
Argument 4 is: "-p2"
Argument 5 is: "2"
Argument 6 is: "-p3"
Argument 7 is: "abc"
Так что cmd.exe
интерпретирует также равныеподписать в качестве разделителя аргументов =
, не находясь внутри двойных кавычекстроковая строкаНу, FOR - это внутренняя команда cmd.exe
, и поэтому тот же код используется для интерпретации списка аргументов пакетного файла, а также набора аргументов FOR .
Подстановка строк поддерживается только cmd.exe
для переменных среды.Невозможно применить их к аргументам пакетного файла или к строкам, присвоенным FOR переменным цикла.
Так что давайте посмотрим на код пакетного файла, который действительно оценивает аргументы:
@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "FileName="
rem Delete all environment variables of which name starts with Parameter.
for /F "delims==" %%I in ('set Parameter 2^>nul') do set "%%I="
:ArgLoop
set "Argument=%~1"
if defined Argument (
if /I "%Argument:~0,2%" == "-p" (
set "Parameter %Argument:~2%=%~2"
shift
) else if not defined FileName (
set "FileName=%~1"
) else (
echo WARNING: Unknown argument: "%~1"
)
shift
goto ArgLoop
)
rem The current argument could be "" which is an empty argument.
rem The current argument could be also just " on being last argument.
rem Don't break the argument loop on such an empty argument, but
rem instead just ignore this empty argument with a warning.
set Argument=%1
if defined Argument (
echo WARNING: Empty argument: %Argument%
shift
goto ArgLoop
)
echo/
if defined FileName echo File name is: "%FileName%"
for /F "tokens=1* delims==" %%I in ('set Parameter 2^>nul') do echo %%I is: "%%~J"
endlocal
Давайте запустим этот командный файл из командной строки:
mysample.bat "" -p1="First Paramter" myfile -p2 "2nd parameter" What's that -p3,ThirdParameter -p4 Fourth value! "
Вывод:
WARNING: Empty argument: ""
WARNING: Unknown argument: "What's"
WARNING: Unknown argument: "that"
WARNING: Unknown argument: "value!"
WARNING: Empty argument: "
File name is: "myfile"
Parameter 1 is: "First Paramter"
Parameter 2 is: "2nd parameter"
Parameter 3 is: "ThirdParameter"
Parameter 4 is: "Fourth"
По моему мнению, этот вывод хорош.Он информирует пользователя о явно неверно указанных аргументах, но обрабатывает, тем не менее, действительные параметры.
Для понимания используемых команд и их работы откройте окно командной строки, выполните там следующие команды и полностью прочитайте всю справкустраницы для каждой команды отображаются очень тщательно.
echo /?
endlocal /?
for /?
goto /?
if /?
rem /?
set /?
setlocal /?
shift /?
Прочтите также статью Microsoft о Использование операторов перенаправления команд для объяснения 2>nul
.Оператор перенаправления >
должен быть экранирован с помощью символа вставки ^
в командной строке FOR , чтобы интерпретироваться как литеральный символ, когда интерпретатор команд Windows обрабатывает эту командную строку перед выполнением команды FOR , котораявыполняет встроенную командную строку set
в отдельном командном процессе, запущенном в фоновом режиме.