Откройте окно командной строки и запустите cmd /?
, чтобы получить справку для командного процессора Windows.Последняя страница справки объясняет в последнем абзаце, когда особенно имя файла (или любая другая строка аргумента) должно быть заключено в двойные кавычки, т.е. строка аргумента содержит пробел или один из этих символов &()[]{}^=;!'+,`~<|>
.Обратите внимание, что <|>
недопустимы в именах файлов / папок, но возможны в общих строках аргументов.
Следующий запуск в окне командной строки call /?
.Справка по выводу объясняет, как можно ссылаться на аргументы пакетного файла, включая ссылку на все переданные аргументы %*
, которая ссылается на все строки аргумента точно так, как они переданы в пакетный файл, за исключением аргумента 0, который точно является именем пакетного файлакак указано пользователем при запуске пакетного файла из окна командной строки.
Теперь давайте рассмотрим очень простой пакетный файл с именем Test.bat
:
@echo off
echo %0 %*
for /F "tokens=3*" %%I in ("%*") do echo FOR: %%I %%J
pause
Test.bat
выполняется из окна командной строки с помощью:
Test 1 2 3 4 5 6
Вторая командная строка выводит в точности строку, как написано выше.
Но что делает FOR вв этом случае?
Выполнение for /?
в окне командной строки выводит справку команды FOR и объясняет параметр /F
, а также значение tokens=3*
.
FOR ожидает здесь строку, заключенную в двойные кавычки, например "..."
с пробелами / табуляциями , а не , содержащие двойные кавычки.Эта строка должна быть разбита на подстроки с использованием пробелов / табуляций, если они не начинаются с символа конца строки (eol) по умолчанию ;
, при этом третья подстрока с пробелом / табуляцией должна быть назначена указанной переменной цикла I
и остаток строки после пробелов / табуляции после третьей подстроки должен быть назначен следующей переменной в соответствии с ASCII таблицей , которая в данном случае будет J
.
Таким образом, результат будет таким, как ожидалось:
Test 1 2 3 4 5 6
FOR: 3 4 5 6
В командной строке FOR выводятся данные о запуске:
Test ;1 2 3 4 5 6
Причиной по умолчанию является eol=;
и точка с запятой в начале строки обрабатывается FOR .Только вторая командная строка выводит используемую командную строку для запуска командного файла.Таким образом, вывод просто: Test ;1 2 3 4 5 6
Далее мы запускаем Test.bat
с:
Test 1 2 3
Вывод:
Test 1 2 3
FOR: 3
Есть пробел навывод строки с помощью FOR .
Но что происходит при запуске командного файла с использованием следующей командной строки?
Test.bat "First argument" "1, 2, 3 in second argument" "^ caret in third argument" "and so on"
Вторая командная строка выводит эту строку.Но FOR должен обработать:
""First argument" "1, 2, 3 in second argument" "^ caret in third argument" "and so on""
FOR не в состоянии полностью интерпретировать эту строку, как вы ожидали, содержащую несколько двойных кавычек, то есть в реальных многократных аргументных строках вустановить для обработки.
Итак, как получить все аргументы, игнорируя первые две строки аргументов, в переменную окружения, разделенную пробелами, для последующей обработки этой строки, объединенной из нескольких строк аргументов пакетного файла?
OneРешение заключается в использовании команды SHIFT в цикле вместе с командой SET .
@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "AllArguments="
:ArgLoop
set "Argument=%~3"
if defined Argument (
set "AllArguments=%AllArguments% %Argument%"
shift /3
goto ArgLoop
)
rem Is there no more argument or is the argument string just empty?
set "Argument=%3"
if defined Argument shift /3 & goto ArgLoop
rem All argument strings processed, remove first space from the concatenated string.
if defined AllArguments set "AllArguments=%AllArguments:~1%"
cls
echo The batch file was called with:
echo/
echo %0 %*
echo/
echo All arguments starting from third argument are:
echo/
echo "%AllArguments%"
echo/
endlocal
pause
Этот пакетный файл с именем Test.bat
, например, выполняется с помощью:
Test.bat "First argument" SecondArgument "^ caret in third argument" "" "Fifth argument!" "1,2,3 | 233 < 234 > 235" "& more arguments" "without or" with,double;quotes=whereby "by mistake last argument has a double" quote at end"
Это действительно ужасный список аргументов для обработки его с помощью пакетного файла.
- В третьей строке аргумента есть escape-символ
^
, интерпретируемый как литеральный символ внутриСтрока аргумента с двойными кавычками. - Четвертая строка аргумента является пустой строкой аргумента.
- В пятом a есть
!
Строка rgument, которая интерпретируется как начало / конец ссылки на переменную среды с задержкой, если отложенное расширение будет включено в пакетном файле даже при нахождении внутри строки аргумента с двойными кавычками. - Следующая строка аргумента содержит разделитель аргументов
,
иоператоры перенаправления |
, <
и >
интерпретируются как литеральные символы из-за нахождения в строке аргумента в двойных кавычках. - Оператор
&
также включен, который имеет несколько значений, например, при перенаправлении с 2>&1
или для несколько команд в одной командной строке , но интерпретируется здесь как буквенный символ, поскольку он также находится внутри двойного строка в кавычках.
- Есть
,
, ;
и =
не внутри строки аргумента с двойными кавычками и поэтому интерпретируются как разделители аргументов cmd.exe
.
- И последний, но не менее важный аргумент заканчивается на
"
, но не начинается на "
.
Вывод этой командной строки с указанным выше командным файлом с 80 столбцами в строке:
The batch file was called with:
Test.bat "First argument" SecondArgument "^ caret in third argument" "" "Fifth a
rgument!" "1,2,3 | 233 < 234 > 235" "& more arguments" "without or" with,double;
quotes=whereby "by mistake last argument has a double" quote at end"
All arguments starting from third argument are:
"^ caret in third argument Fifth argument! 1,2,3 | 233 < 234 > 235 & more argume
nts without or with double quotes whereby by mistake last argument has a double
quote at end""
Хорошо выглядит, не правда ли.
Кстати: было бы неплохо выводить значение %AllArguments%
без использования двойных кавычек в этом случае, потому что все эти символы имеют специальные значения для cmd.exe
вне строки аргумента с двойными кавычками. Но можно заменить echo "%AllArguments%"
на setlocal EnableDelayedExpansion & echo !AllArguments!& endlocal
, чтобы вывести строковое значение переменной среды AllArguments
без двойных кавычек с использованием отложенного раскрытия. См. Также Как синтаксический анализ сценариев интерпретатора команд Windows (CMD.EXE)?
Примечание 1: Команда SHIFT не изменяет строку всех переданных аргументов , на которую ссылается %*
, как показывает этот пакетный файл. Он изменяет только нумерованные ссылки на аргументы, используемые этим пакетным файлом для обработки всегда третьего аргумента в цикле, пока на самом деле не останется больше аргументов.
Примечание 2: Максимальный размер переменной среды составляет 8192 байта, включая байты для имени переменной, один знак равенства (разделитель между именем и значением) и завершающий нулевой байт строку. Другими словами, максимальная длина, назначаемая переменной среды, равна: 8192 - 2 - длина имени переменной
Чтобы понять используемые команды и то, как они работают, откройте окно командной строки, выполните там следующие команды и полностью прочитайте все страницы справки, отображаемые для каждой команды.
call /?
cls /?
echo /?
endlocal /?
goto /?
if /?
rem /?
set /?
setlocal /?
shift /?
PS: Я совершенно уверен, что этот код все еще не обрабатывает все комбинации аргументов правильно, но он должен работать почти во всех случаях использования.