Экранирование двойной кавычки в опции `delims` для`for /F`
У меня возникли некоторые проблемы с пакетным скриптом, который должен проанализировать значение из файла конфигурации в переменную.
Соответствующая анонимность, соответствующая строка файла выглядит так
<?define ProductShortName="Foo" ?>
Я хочу установить переменную в Foo
, Строка ProductShortName
достаточно уникален, чтобы получить линию с findstr
, но тогда я должен извлечь значение. Правильный подход, кажется, for /F
, но все следующие ошибки дают ошибки:
for /F "delims=^" usebackq" %%G in (`findstr /L "ProductShortName" "%~dp0Installer\Branding.wxi"`)
for /F "delims="" usebackq" %%G in (`findstr /L "ProductShortName" "%~dp0Installer\Branding.wxi"`)
for /F "delims=\" usebackq" %%G in (`findstr /L "ProductShortName" "%~dp0Installer\Branding.wxi"`)
for /F 'delims=^" usebackq' %%G in (`findstr /L "ProductShortName" "%~dp0Installer\Branding.wxi"`)
for /F 'delims=" usebackq' %%G in (`findstr /L "ProductShortName" "%~dp0Installer\Branding.wxi"`)
for /F "delims=" usebackq" %%G in (`findstr /L "ProductShortName" "%~dp0Installer\Branding.wxi"`)
в основном по линии
usebackq" %G in (`findstr /L "ProductShortName" "C:\foo\bar\Installer\Branding.wxi"`) was unexpected at this time.
Какой правильный способ избежать этого, чтобы разбить строку на "
?
7 ответов
Вы можете использовать двойные кавычки в качестве разделителя с синтаксисом вроде:
FOR /F delims^=^"^ tokens^=2 %G IN ('echo I "want" a "pony"') DO @ECHO %G
При запуске в командной строке, используя tokens^=2
должен дать вам want
и 4 жетона дают вам пони.
Применяя методику к исходному вопросу, это должно работать в вашем командном файле:
FOR /F delims^=^"^ tokens^=2 %%G IN ('FINDSTR /L "ProductShortName" "data.txt"')
подробности
Я не эксперт по причудам парсера командной строки, но это может помочь подумать об обычном "delims=blah tokens=blah"
как единый объединенный аргумент, переданный FOR. Трюк с выходом delims^=blah^ tokens^=blah
обходит необходимость заключать в кавычки, все еще рассматривая последовательность как один аргумент. Я использовал немного творческой аналогии, и эффект не универсален для всей оболочки. Например, вы не можете сделать dir C:^\Program^ Files
(что имеет смысл, так как ^
является допустимым символом имени файла).
Тестовые случаи
Достаточно экранирования, вы можете быстро проверить исходный пример в командной строке:
FOR /F delims^=^"^ tokens^=2 %G IN ('echo ^^^<?define ProductShortName="Foo" ?^^^>') DO @ECHO %G
Другие, кто играет с этим, могут захотеть создать файл testcases.txt:
blah blah "red"
blah "green" blah
How about a "white" "unicorn"?
и запустить что-то вроде:
FOR /F delims^=^"^ tokens^=2 %G IN (testcases.txt) DO @ECHO %G
проверить результаты для различных входов. В этом случае должно получиться:
red
green
white
Последний пример:
FOR /F delims^=^"^ tokens^=2 %G IN ('FINDSTR /L "unicorn" "testcases.txt"') ^
DO @ECHO The unicorn is %G.
Наконец, обратите внимание, что мое тестирование для этого было сделано на Windows Server 2003.
РЕДАКТИРОВАТЬ: Это неправильно, см. Мой комментарий позже: Как сказал Джои, кажется, нет возможности использовать кавычку в качестве разделителя, она может использоваться только как символ EOL.
Похоже, это является следствием синтаксического анализатора FOR-LOOP в cmd.exe, так как он сканирует часть параметров и останавливает сканирование после кавычки, только параметр EOL= прерывает это, поскольку он всегда читает следующий символ без каких-либо ожиданий.,
Вы можете решить эту проблему с помощью обходного пути, такого как icabod.
Решение состоит в том, чтобы заменить кавычки неиспользованным символом, но если вы хотите принять какой-либо символ внутри кавычек, там не будет неиспользуемого символа.
Таким образом, мое решение сначала создает неиспользуемый символ, заменяя все предыдущие вхождения.
Я хочу использовать #
заменить цитаты, но сохранить все #
внутри кавычек заменить его раньше $R
, но тогда он может столкнуться с существующим $R
в тексте, поэтому я сначала заменяю все $
с $D
, то это абсолютно без столкновений.
После извлечения "цитируемого" текста я должен заменить $R и $D на их исходные значения, вот и все.
@echo off
setlocal EnableDelayedExpansion
for /F "tokens=1,2" %%1 in ("%% #") DO (
for /f "tokens=* usebackq" %%a in ("datafile.txt") do (
set "z=%%a"
set "z=!z:$=$D!"
set "z=!z:#=$R!"
set "z=!z:"=#!"
for /f "tokens=1-3 delims=#" %%a in ("!z!") do (
set "value=%%b"
if defined value (
set "value=!value:$R=#!"
set "value=!value:$D=$!"
echo result='!value!'
)
)
)
)
Пример текста:<?define ProductShortName="Two #$* $D $R" ?>
результаты к Two #$* $D $R
как и ожидалось
РЕДАКТИРОВАТЬ: Есть способ!
Я всегда проверял такие вещи (и это не удается)
setlocal EnableDelayedExpansion
set "var=one"two"three"
FOR /F ^"tokens^=1-3^ delims^=^"^" %%a in ("!var!") do echo %%a--%%b--%%c
Но, удалив первую цитату, все работает.
setlocal EnableDelayedExpansion
set "var=one"two"three"
FOR /f tokens^=1-3^ delims^=^" %%a in ("!var!") do echo %%a--%%b--%%c
Я не верю, что это возможно - цитата ("
) нельзя использовать в качестве разделителя.
Однако одним из решений является сохранение всей строки в переменной окружения и использование встроенной функции замены set
заменить цитату на что-то другое - например _
, Затем вы можете использовать другой цикл for только для этой строки, чтобы разделить новый разделитель:
setlocal EnableDelayedExpansion
for /f "tokens=* usebackq" %%a in (`...`) do (
set z=%%a
set z=!z:"=_!
for /f "tokens=1-3 delims=_" %%a in ("!z!") do echo %%b
)
Небольшое объяснение... первое for
цикл получает всю строку в %a
переменная. Затем это копируется в переменную z
, z
затем устанавливается снова, используя встроенную функцию поиска / замены (обратите внимание, что здесь мы ссылаемся на переменную, используя !z:"=_!
, что делает замену). Наконец, мы анализируем эту единственную строку, чтобы получить элемент между кавычками.
Я надеюсь, что это имеет какой-то смысл.
Я не нашел способ сделать это возможным. Может быть, Джеб знакомит с более глубокими знаниями, чем я. Кроме того, можно нарезать линию, используя =
и пробел в качестве разделителей и просто удалите кавычки вокруг результата:
for /f "tokens=3 usebackq delims== " %G in (`...`) do @echo %~G
Я думаю, что в основном легче найти символы, которые окружают кавычки, и удалить цитату на более позднем этапе. Если мы хотим извлечь значения из определенной строки в файле XML
<line x0="745" y0="1162" x1="1203" y1="1166"/>
Мы поступаем так
SETLOCAL ENABLEDELAYEDEXPANSION
FOR /F "tokens=3,5,7,9 delims==/ " %%i IN ('FINDSTR line %1') DO (
SET x0=%%~i
SET y0=%%~j
SET x1=%%~k
SET y1=%%~l
)
В общем, кавычки не являются реальными разделителями для себя, поэтому в большинстве случаев это поможет.
У меня недавно была проблема, похожая на эту. Примеры в ответах слишком сложны и трудны для чтения. В итоге я обернул команду и ее функциональность в другой сценарий CMD, а затем вызвал его из файла . Вот пример команды:
wmic fsdir where name="C:\\some\\path\\to\\a\\folder" get creationdate
Путь был извлечен и передан как переменная, а выходные данные захвачены и установлены вDO
раздел дляFOR /F
вызывающего скрипта. Это привело к более читабельному подходу и снижению сложности.
Надеюсь, это поможет кому-то в будущем.
Просто избегайте двойных кавычек, используя ^
экранировать все символы в строке (включая пробелы). Таким образом, вы можете добавить двойную кавычку в качестве параметра.
for /F Tokens^=1^,2^-5^*^ Delims^=^" %%i in ( ...
Это должно работать.