Как обработать закрывающую скобку в именах путей в цикле for? - PullRequest
5 голосов
/ 19 ноября 2011

У меня есть длинный путь к программе, которую я должен запустить в цикле for / f, который включает закрывающую скобку ")" и из которой мне нужно проанализировать вывод:

for /f "tokens=1" %%G in ('"C:\Documents and Settings\myaccount\Desktop\Test_release (x86)\program.exe" list') do (echo Will do something with %%G)

... где 'list' - это параметр, переданный моей программе. Я получаю сообщение об ошибке «C: \ Documents» не распознается как внутренняя или внешняя команда, работающая программа или командный файл. »

Я знаю проблема в том, что закрывающая скобка фактически закрывает блок «for», поэтому конечные двойные кавычки не «видны», поэтому длинное имя пути не заключено в двойные кавычки больше. Что я не понимаю, так это , почему это происходит, поскольку мой путь заключен в двойные кавычки? Я также попробовал опцию usebackq:

for /f "usebackq tokens=1" %%G in (`"C:\Documents and Settings\myaccount\Desktop\Test_release (x86)\program.exe" list`) do (echo Will do something with %%G)

... без лучших результатов. Я пытался сбежать, как этот "^)" или как этот "^^)", ничего не делать Попробовал удвоить двойные кавычки:

for /f "tokens=1" %%G in ('""C:\Documents and Settings\myaccount\Desktop\Test_release (x86)\program.exe"" list') do (echo Will do something with %%G)

Все еще не работает.

Более того, я на самом деле использую переменную, которая содержит путь, который неизвестен заранее (построен из% CD%), и EnableDelayedExpansion активирован. Я пробовал отложенное расширение (которое исправляло подобные проблемы в других ситуациях), чтобы предотвратить расширение переменной во время чтения и задержать его во время выполнения:

setlocal EnableDelayedExpansion
set _var=%CD%\program.exe
@REM _var now contains C:\Documents and Settings\myaccount\Desktop\Test_release (x86)\program.exe
for /f "tokens=1" %%G in ('"!_var!" list') do (echo %%G)
endlocal

Все еще не работает, не понимаю почему.

Но , удваивая двойные кавычки с задержкой раскрытия в приведенном выше коде:

for /f "tokens=1" %%G in ('""!_var!"" list') do (echo %%G)

работает! ... почему ... зачем это делать ??? Какой эффект это имеет? Я не понимаю Я также боюсь, что это может вызвать проблемы в некоторых конкретных обстоятельствах ...

Есть идеи?

Ответы [ 2 ]

5 голосов
/ 20 ноября 2011

Комментарии в ответах на этот вопрос указывают на то, что XP работает иначе, чем более новые версии Windows.

В XP существует известная ошибка FOR / F: http://www.dostips.com/forum/viewtopic.php?p=9062#p9062. Но эта проблема не связана с этой ошибкой.

Фактическая проблема связана с тем, как FOR / F выполняет команду в предложении IN (). Он использует CMD \C command (см. Как синтаксический анализ сценариев интерпретатора команд Windows (CMD.EXE)? )

Вы можете наблюдать это поведение, добавив эту строку в пример PROC.BAT Aacini.

echo cmdcmdline=%cmdcmdline%

Следующая проблема касается того, как CMD работает с кавычками, которые появляются в команде / C, и почему XP ведет себя иначе, чем в более поздних версиях Windows.

Эта команда не работает в XP, но успешно в Vista и за ее пределами:

for /f "delims=" %a in ('"test (this)\prog" args') do @echo %a

Команда, которую FOR пытается выполнить (% cmdcmdline%), одинакова в обеих версиях (не учитывая различия в% COMSPEC%):

C:\Windows\system32\cmd.exe /c "test (this)\prog" args

XP имеет недостаток в дизайне CMD в том, как он работает с кавычками. Недостаток даже зарегистрирован (но это не признано недостатком). Vista и более поздние версии частично исправляют недостатки в дизайне, но не стоит исправлять документацию.

Вот выдержка из справки CMD

If /C or /K is specified, then the remainder of the command line after
the switch is processed as a command line, where the following logic is
used to process quote (") characters:

    1.  If all of the following conditions are met, then quote characters
        on the command line are preserved:

        - no /S switch
        - exactly two quote characters
        - no special characters between the two quote characters,
          where special is one of: &<>()@^|
        - there are one or more whitespace characters between the
          two quote characters
        - the string between the two quote characters is the name
          of an executable file.

    2.  Otherwise, old behavior is to see if the first character is
        a quote character and if so, strip the leading character and
        remove the last quote character on the command line, preserving
        any text after the last quote character.

Мы хотим, чтобы CMD следовал правилу 1, чтобы кавычки были сохранены, но ( и ) нарушают ограничение специальных символов в XP, поэтому следует правило 2, и CMD пытается выполнить

test (this)\prog args

Должно быть совершенно очевидно, почему это не получается!

Я не могу придумать ни одной причины, по которой в правиле 1 существует ограничение специальных символов. Оно разрушает всю цель того, что пытается сделать MS.

Очевидно, что недостаток дизайна частично исправлен в Vista и более поздних версиях, но они не обновили документацию HELP. Vista игнорирует специальные символы ( и ) и обрабатывает команду, используя правило 1, кавычки сохраняются и все работает.

Обновление 2015-05-17: К сожалению, Vista и более поздние версии по-прежнему воспринимают @, ^ и & как специальные символы, хотя они являются действительными символами в именах файлов. Конечно, <, > и | обрабатываются как специальные символы, но в любом случае они недопустимы в имени файла. Таким образом, для Vista и выше документация для правила 1 должна читаться как where special is one of: &<>@^|.

Я проследил поведение, которое каждый задокументировал, и все это соответствует вышесказанному.

Существует способ выполнить команду в XP без использования отложенной переменной расширения, и она совместима с Vista и более поздними версиями.

for /f "delims=" %a in ('^""test (this)\prog" args^"') do @echo %a

Открывающие и закрывающие кавычки экранируются, поэтому ) не мешает анализатору FOR. Команда, которая выполняется для предложения IN ():

C:\Windows\system32\cmd.exe /c ""test (this)\prog" args"

Как XP, так и Vista следуют правилу 2, поскольку существует более двух кавычек, поэтому CMD выполняет

"test (this)\prog" args

и все работает!

Остальная часть этого ответа устарела, но сохранилась, чтобы дать контекст существующим комментариям.

<ч />

Ваш первый пример кода должен работать; он не может (сделать, что не должен) выдавать сообщение об ошибке, которое вы описываете. Сообщение об ошибке разрывает путь в первом пробеле, что означает, что путь не был заключен в кавычки или не был экранирован. Но вы «уверены», что это было указано.

Ключ к проблеме - три части информации в конце вашего сообщения:

  1. Вы на самом деле используете переменную с отложенным расширением

  2. это не работает: for /f "tokens=1" %%G in ('"!_var!" list') do (echo %%G)

  3. это работает: for /f "tokens=1" %%G in ('""!_var!"" list') do (echo %%G)

Если значение var уже заключено в кавычки, вы получите описываемое вами поведение.

Значение вашей переменной должно быть "C:\Documents and Settings\myaccount\Desktop\Test_release (x86)\program.exe", включая кавычки.

Чтобы сделать это объяснение более читабельным, я сокращу путь до "test (this)\prog.exe"

"!var!" терпит неудачу, потому что он расширяется до ""test (this)\prog.exe"", что фактически приводит к заключению в кавычки пути. Строка имеет три области: две в кавычках и одну в середине, которая не является:

" пустая область в кавычках " путь без кавычек " пустая область в кавычках "

""!var!"" работает, потому что расширяется до """test (this)\prog.exe""" и путьтеперь снова цитируется.Теперь в строке есть пять областей:

" пустая область в кавычках " пустая область без кавычек " путь в кавычках " пустая область без кавычек " пустаяобласть в кавычках"

Простой ответ о том, как вам следует поступить:

Если значение var уже заключено в кавычки, просто используйте !var! Edit - это не работает на XP: "! Var!"работает на обоих

Если значение var не заключено в кавычки, используйте "!var!" Edit - это не работает на XP: ""! var!"" работает на обоих

1 голос
/ 21 ноября 2011

Я провел несколько тестов, чтобы выяснить, почему прямой метод, который вы использовали вначале, не работал. Сначала я создал каталог с именем test (this) и внутри него я создал командный файл с именем prog.bat:

>dir /b
test (this)
>dir /b "test (this)"
prog.bat
>type "test (this)\prog.bat"
@echo off
echo/One - Line one of prog
echo/Two - Line two of prog
echo/Three - Line three of prog

Затем я впервые попытался получить доступ к содержимому такого файла с помощью for /f. Обратите внимание, что опция useback обязательна, поскольку имя файла содержит пробелы и должно быть заключено в кавычки:

>for /f "usebackq tokens=1" %G in ("test (this)\prog.bat") do @echo %G
@echo
echo/One
echo/Two
echo/Three

Предыдущий результат доказывает, что путь указан правильно. Теперь, чтобы выполнить пакетный файл вместо чтения, просто заключите его имя в кавычки, верно?

>for /f "usebackq tokens=1" %G in (`"test (this)\prog.bat"`) do @echo %G
'test' is not recognized as an internal or external command,
operable program or batch file.

Затем, поскольку в сообщении говорилось, что test - это имя команды, не найденной, я создал пакетный файл с именем test.bat:

>type test.bat
@echo off
echo Test.batFileLine1
echo Test.batFileLine2
echo Test.batFileLine2

>for /f "usebackq tokens=1" %G in (`"test (this)\prog.bat"`) do @echo %G
Test.batFileLine1
Test.batFileLine2
Test.batFileLine2

Aha! Предыдущий результат показывает, что в этом случае кавычки игнорируются и выполняется только test (this)\prog.bat, верно?

>for /f "usebackq tokens=1" %G in (`test (this)\prog.bat`) do @echo %G
\prog.bat`) was unexpected at this time.

И что теперь? Ну, проблема СЕЙЧАС связана с круглыми скобками:

>for /f "usebackq tokens=1" %G in (`test ^(this^)\prog.bat`) do @echo %G
Test.batFileLine1
Test.batFileLine2
Test.batFileLine2

Мой вывод заключается в том, что команда for /f имеет ошибку, когда используются как обратные кавычки, так и кавычки в сочетании с параметром «usebackq», а имя файла содержит пробелы, и что эта ошибка не указывается, если используется расширение с отложенной переменной .

...