#windows #batch-file #cmd
#Windows #пакетный файл #cmd
Вопрос:
Я пытаюсь написать пакетный скрипт под Windows 10, который переходит во все подкаталоги, содержащие файл с именем «Makefile», и выполняет там команду «make». Команда make находится на моем пути.
У меня есть следующий скрипт, который завершается с ошибкой, если путь содержит пробел:
@echo off
setlocal ENABLEDELAYEDEXPANSION
for /f %%i in ('dir /b /s Makefile') do (
cd "%%~pi"
make
if errorlevel 1 exit /b %errorlevel%
cd ..
)
Если путь к каталогу, в котором я запускаю скрипт, содержит пробел, «%%~ pi», хотя и заключенный в кавычки, кажется, сокращает подкаталоги, начиная с того, который содержит пробел.
Пример:
Предполагая, что файл есть «C:UsersUsernameDocumentsspace каталог srcMakefile»
При выполнении вышеуказанного batchscript из каталога «space dir» он пытается выполнить команду make в каталоге «C:UsersUsernameDocumentsspace реж», забыв о «src»
Как я могу решить эту проблему или какой будет альтернативный пакетный скрипт, который выполняет эту работу?
Комментарии:
1. Вместо
for /f %%i in ('dir /b /s Makefile') do (
, используйтеfor /f "delims=" %%i in ('dir /b /s /a:-d "makefile"') do (
, затем вместоcd "%%~pi"
иcd ..
, используйтеpushd "%%~i"
, иpopd
соответственно. Я бы также задался вопросом, хотите ли вы, чтобыexit
при любой ошибке, которая препятствовала бы любым другимmake
командам, в дереве было несколькоmakefile
s.2. Потрясающе, этот подход работает. Однако
%%i
переменная по-прежнему проходит через имена файлов, поэтому она должна бытьpushd "%%~pi
вместоpushd "%%~i"
. Не могли бы вы предоставить свой комментарий в качестве ответа, чтобы я мог его принять?3. Извиняюсь, это была опечатка, которую я намеревался использовать
pushd "%%~dpi"
(редко возникает необходимость пропуститьd
) . Не стесняйтесь отвечать самостоятельно, если считаете, что это было бы полезно будущим читателям. Для меня мне не нужны точки, и IMO, ваше решение просто заключается в том, что вы не реализовали вывод информации при вводе опции справки команд,for /?
.4.
if errorlevel 1 exit /b %errorlevel%
не будет действовать так, как ожидалось, поскольку%errorlevel%
будет заменено его значением во времяfor
анализа. Поскольку вы включили delayedexpansion, используйтеif errorlevel 1 exit /b !errorlevel!
Ответ №1:
Благодаря комментариям Compo и Magoo я смог собрать следующее рабочее решение:
@echo off
setlocal ENABLEDELAYEDEXPANSION
for /f "delims=" %%i in ('dir /b /s /a:-d "Makefile"') do (
pushd "%%~dpi"
make
if errorlevel 1 exit /b !errorlevel!
popd
)
Объяснение улучшений:
Наиболее важным исправлением является добавление "delims="
в for
цикл. Это не позволяет for
циклу разбирать строки на токены, что позволяет избежать разделения, вызванного пробелами в пути.
Добавленная опция /a:-d
не позволяет dir
команде указывать путь, где Makefile — это имя каталога вместо имени файла.
Использование pushd
и popd
является элегантным и более безопасным способом посещения подкаталогов, и при завершении сценария сохраняется исходный рабочий каталог.
!errorlevel!
(вместо %errorlevel%
) обеспечивает расширение переменной в нужное время.