Комментарии в ответах на этот вопрос указывают на то, что 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
и все работает!
Остальная часть этого ответа устарела, но сохранилась, чтобы дать контекст существующим комментариям.
<ч />
Ваш первый пример кода должен работать; он не может (сделать, что не должен) выдавать сообщение об ошибке, которое вы описываете. Сообщение об ошибке разрывает путь в первом пробеле, что означает, что путь не был заключен в кавычки или не был экранирован. Но вы «уверены», что это было указано.
Ключ к проблеме - три части информации в конце вашего сообщения:
Вы на самом деле используете переменную с отложенным расширением
это не работает: for /f "tokens=1" %%G in ('"!_var!" list') do (echo %%G)
это работает: 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!"" работает на обоих