Как разделить строки с двойными кавычками со встроенными пространствами, разделенными пробелами в пакетном файле?
Я борюсь с улучшением script, который я предложил в качестве ответа Как написать пакетный файл с указанием пути к исполняемому файлу и версии Python для обработки сценариев Python в Windows? вопрос. Чтобы предотвратить диалоговое окно Open With, я хотел бы прочитать вывод команды ftype
, извлечь путь для
выполнимый из него и проверить, существует ли он.
После этого
@echo off
setlocal EnableDelayedExpansion
rem c:\ftype Python.File ->
rem Python.File="c:\path with spaces, (parentheses) and % signs\python.exe" "%1" %*
for /f "tokens=2 delims==" %%i in ('ftype Python.File') do (
set "reg_entry=%%i"
)
reg_entry's
Содержимое
"c:\path with spaces and (parentheses) and % signs\python.exe" "%1" %*
Как мне разделить это, чтобы получить
"c:\path with spaces, (parentheses) and % signs\python.exe"
, "%1"
и %*
?
ИЗМЕНИТЬ
Я пробовал использовать call
после прочтения ответа Aacini, и он почти работает. Однако он не обрабатывает знак %
.
@echo off
setlocal EnableDelayedExpansion
set input="c:\path with spaces and (parentheses) and %% signs\python.exe" "%%1" %%*
echo !input!
call :first_token output !input!
echo !output!
goto :eof
:first_token
set "%~1=%2"
goto :eof
Выход
"c:\path with spaces and (parentheses) and % signs\python.exe" "%1" %*
"c:\path with spaces and (parentheses) and 1"
Ответы
Ответ 1
Альтернативный синтаксический анализатор, который очень похож на парсер CALL, является простым FOR. Существуют два осложняющих фактора:
1- Функция FOR не должна быть расширена, если расширенное расширение включено, если оно содержит !
. Это легко обрабатывается.
2- Содержимое не должно содержать подстановочные знаки *
или ?
. ?
можно временно заменить, а затем возвратить. Но нет простого способа поиска и замены *
.
Поскольку эта проблема пытается разобрать путь, а пути не могут содержать подстановочные знаки, эту проблему легко решить без использования CALL. Я добавил !
в тестовый пример для полноты.
@echo off
setlocal disableDelayedExpansion
set input="c:\path with spaces, ampersand &, carets ^ and (parentheses)! and %% signs\python.exe" "%%1" %%*
set input
set "output="
setlocal enableDelayedExpansion
for %%A in (!input!) do if not defined output endlocal & set output=%%A
set output
Если мы можем положиться на то, что первый токен всегда будет заключен в кавычки, тогда решение еще проще. Мы можем использовать FOR/F с EOL и DELIMS, установленными на "
.
@echo off
setlocal disableDelayedExpansion
set input="c:\path with spaces, ampersand &, carets ^ and (parentheses)! and %% signs\python.exe" "%%1" %%*
set input
set "output="
setlocal enableDelayedExpansion
for /f eol^=^"^ delims^=^" %%A in ("!input!") do endlocal & set output="%%A"
set output
Однако я просто посмотрел на мой вывод FTYPE и обнаружил, что некоторые записи не цитировались, даже если они содержат пробелы в пути! Я не думаю, что любой из ответов на этой странице справится с этим. На самом деле все предпосылки, стоящие за вопросом, могут быть ошибочными.
Ответ 2
Это прямая возможность пакета. В Batch параметры Batch файла разделяются пробелами, а параметр может быть заключен в кавычки, поэтому просто передайте значение reg_entry в качестве параметров пакетного файла внутри каждого из них:
C:\>type test.bat
@echo off
:loop
echo %1
shift
if not "%1" == "" goto loop
.
C:\>echo %reg_entry%
"c:\path with spaces and (parentheses) and % signs\python.exe" "%1" %*
.
C:\>test %reg_entry%
"c:\path with spaces and (parentheses) and % signs\python.exe"
"%1"
%*
Ответ 3
По существу, вам нужно преобразовать всю строку в свои элементы, как это сделал бы синтаксический анализатор. В вашем случае лексический анализ, вероятно, сделает трюк из-за правил Windows, где разрешены пробелы.
В принципе вам нужно построить конечный конечный автомат в вашем .cmd файле с метками и условными gotos. FSA имеет состояния, которые обрабатывают различные части элемента, который вы хотите собрать. В начальном состоянии вы решаете, видите ли вы пробел (пропустите и вернитесь к началу), двойную кавычку (перейдите к части FSA, которая обрабатывает строки с двумя кавычками) или что-то непустое (перейдите в часть FSA, который собирает непустые символы).
Часть FSA, которая собирает строки с двойными кавычками, отбирает символы, пока не найдет другую двойную кавычку; это позволяет записывать пробелы внутри строк с двойным цитированием. Я думаю, вам нужно проверить "сбежавшую" двойную кавычку (две из них в строке), и если она найдена, замените их на одну двойную кавычку и продолжайте собирать символы.
Это довольно уродливо, потому что CMD script имеет действительно ужасные возможности обработки строк. Каждая (уродливая) вещь, которую вы должны знать, можно найти, набрав HELP SET
в командной строке DOS. В частности, подстрока имеет вид %VAR:~n,m%
, который выделяет символы m
, начинающиеся с индекса n
в переменной окружения %VAR%
. Я нашел это полезным для SET TEMP=%VAR%
, а затем отключил символы %TEMP%
один за другим с помощью простых последовательностей, таких как
SET CHAR=%TEMP:~0,1%
SET TEMP=%TEMP:~1%
Enjoy.
Ответ 4
Как сказал Аачини, ваша проблема может быть решена с помощью разделения внутренних параметров с помощью инструкции CALL
.
Чтобы избежать потери %
знаков с помощью CALL
, вы можете удвоить их перед расширением CALL
.
Ключевая строка set "input=!input:%%=%%%%!"
, процентные знаки наполовину находятся в одной из фаз парсера, поэтому заменяются одиночные %
на %%
.
Но даже тогда это решение не идеально!
Это решение имеет проблемы со специальными символами типа &<>|
, в вашем случае только &
, так как это единственный законный символ в имени файла/пути.
Этого можно избежать, изменив строку set "%~1=%2"
на set ^"%~1=%2"
, это гарантирует, что% 2 использует окружающие кавычки.
Но теперь у вас другая проблема, все карьеры удвоены,
поэтому я должен сделать еще одну замену для вывода с помощью set "output=!output:^^=^!"
.
Новый код будет выглядеть следующим образом:
@echo off
setlocal EnableDelayedExpansion
set input="c:\path with spaces, exlcamation mark^!, ampersand &, carets ^ and (parentheses) and %% signs\python.exe" "%%1" %%*
echo !input!
set "input=!input:%%=%%%%!"
call :first_token output !input!
set "output=!output:^^=^!"
echo !output!
goto :eof
:first_token
set ^"%~1=%2"
goto :eof
EDIT: для обработки также восклицательных знаков !
Вам нужно изменить функцию :first_token
на
:first_token
setlocal DisableDelayedExpansion
set ^"temp=%2"
set ^"temp=%temp:!=^!%"
(
endlocal
set ^"%~1=%temp%"
)
goto :eof