Почему forfiles проглатывает первый аргумент команды?

Я пытаюсь сделать что-то похожее на Получить Visual Studio для запуска шаблона T4 для каждой сборки, используя cmd forfiles, чтобы преобразовать каждый шаблон в VS2008.

Если я выполняю

forfiles /m "*.tt" /s /c "\"%CommonProgramFiles(x86)%\Microsoft Shared\TextTemplating\1.2\TextTransform.exe\" @file"

тогда я получаю сообщение об ошибке TextTransform.exe (экран текста, объясняющий, как передать его в качестве аргументов).

Если я вместо этого выполняю

forfiles /m "*.tt" /s /c "cmd /c echo Transforming @path && \"%CommonProgramFiles(x86)%\Microsoft Shared\TextTemplating\1.2\TextTransform.exe\" @file"

тогда он отлично работает.

Чтобы отладить это, я создал простую программу командной строки под названием debugargs, которая просто печатает количество аргументов, которые оно получает, и их значения. Затем некоторые эксперименты показывают, что первая форма прямого прохождения команды до forfiles вызывает проглатывание первого аргумента. Например.

forfiles /m "*.tt" /s /c "debugargs.exe 1 2 3"

выводит вывод

2 arguments supplied
#1: 2
#2: 3

документация Я смог найти довольно редкий вариант, и я не вижу упоминания об этом как возможности. Это просто непонятная ошибка, или я чего-то не хватает?

Ответ 1

Это кажется ошибкой в ​​способе forfiles вызывает .exe s. В ожидании я расширил программу debugargs, чтобы напечатать полную командную строку.

X:\MyProject>forfiles /m "*.tt" /s /c "debugargs.exe 1 2 @file"

2 arguments supplied
#1: 2
#2: Urls.tt
Full command line: 1 2 "Urls.tt"

Таким образом, наиболее подходящим решением будет удвоение исполняемого имени:

forfiles /m "*.tt" /s /c "debugargs.exe debugargs.exe 1 2 @file"

Альтернативным решением является вызов cmd /c. Однако обратите внимание, что если вам нужно процитировать исполняемый путь (например, потому что он содержит пробел), вам потребуется дополнительное обходное решение для добавления @:

forfiles /m "*.tt" /s /c "cmd /c @\"debugargs.exe\" 1 2 @file"

Ответ 2

Я воспроизвел и поведение в файлах. Вы можете обойтись, используя команду cmd/c перед командой, или вы можете перейти на PowerShell, где эквивалентная команда будет что-то вроде этого (не проверена):

get-childitem . -filter "*.tt" -recurse | foreach-object {
  & "${ENV:CommonProgramFiles(x86)}\Microsoft Shared\TextTemplating\1.2\TextTransform.exe" "`"$($_.Name)`""
}

Билл

Ответ 3

Я тоже борется с этим. Обход, который я нашел, - это просто добавить дополнительное пространство между командой и первым аргументом! Итак, где я пытался:

FORFILES /s /m *.dll /c "python \"c:\path\to\script.py\" -t arg1 etc"

python пытался найти файл "arg1" для выполнения, но если я просто изменил его на:

FORFILES /s /m *.dll /c "python  \"c:\path\to\script.py\" -t arg1 etc"

это действительно работает!