Пакетное перемещение во все подкаталоги, содержащие Makefile, и выполнение make там; не работает с пробелом в path

#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% ) обеспечивает расширение переменной в нужное время.