Вопрос: Пакетный файл для запуска .exe, когда определенное количество файлов находится в контролируемой папке


Я пытаюсь написать пакетный файл, который будет запускать exe всякий раз, когда в папке имеется ровно 4 изображения jpg. Впоследствии изображения должны быть удалены.

Мне кажется, что это работает, но файл запускает exe снова и снова. Кажется, я не могу окунуться в голову, что это за ошибка.

Любая помощь очень ценится!

@echo off
setlocal EnableDelayedExpansion
set counter=0

:loop
cd "c:\JPGfolder\"
for %%B in (*) do set /a counter+=1
echo File Count = !counter!

if !counter! EQU 4 (
for /f "delims=|" %%I in ('DIR "c:\JPGfolder\" /B /O:-D *.jpg') DO (
SET NewestFile=%%I
echo Newest File = "c:\JPGfolder\!NewestFile!"
start "" /w "c:\programs\generate.exe" "c:\JPGfolder\"%NewestFile%
del c:\JPGfolder\*.jpg
GOTO :BREAK
)
)

:BREAK
set /a counter=0

ping -n 2 localhost >nul

) else (
 echo No Files Found
 rem pause
 goto :loop
)
goto :loop

2
2017-09-15 19:13


Источник




Ответы:


Я вижу ряд проблем с вашим кодом. Но я не вижу, как вы получаете описанное вами поведение.

1) Вы считаете все файлы, но ваш код, чтобы получить самую новую и удалить все, работает только с .jpg файлами. Ваш счет также должен быть ограничен .jpg файлами.

2) Вы забыли использовать задержанное расширение в своей строке START. Но на самом деле нет необходимости использовать значение среды вообще. Вы можете просто использовать %%I напрямую, поэтому отсроченное расширение не требуется. Кроме того, весь путь к файлу должен быть заключен в кавычки.

3) У вас есть дополнительный ) который рано закрывает ваш запрос IF. ) ELSE ( а также ) строки просто игнорируются, а строки между ними выполняются безоговорочно. Это нечетная причуда парсерного анализатора. Если синтаксический анализатор ищет команду, и не существует открытого блока круглых скобок, тогда ) и все после него на этой линии просто игнорируются.

4) Если вы исправите свои круглые скобки, удалив один из ) линий, то у вас все еще есть проблема, потому что вы GOTO метку в сложной инструкции IF. Если команды ELSE нарушены GOTO так же, как и с операторами FOR / F. Видеть https://stackoverflow.com/q/8481558/1012053 для получения дополнительной информации.

5) В вашем заявлении на компакт-диске должен использоваться параметр / D, только если вы находитесь на другом томе. Либо это, либо используйте PUSHD вместо этого.

6) Ваше сообщение «Нет файлов найдено» неверно - оно действительно должно сказать «Количество файлов <> 4»

7) У вашего алгоритма есть фундаментальный недостаток. Что делать, если у вас есть файлы 3.jpg, когда ваш код сначала проверяет, а затем, когда он проверяет снова, есть 5 файлов .jpg? Ваш код никогда не увидит счет 4!

Возможны также некоторые упрощения.

8) Поскольку вы установили текущий каталог в папку «c: \ JPGfolder», вам больше не нужно указывать путь к файлу каждый раз. Вы можете просто использовать %%~fI чтобы получить полный путь.

9) Я бы перенесла инициализацию счета до :LOOP метка. Тогда вам не нужно беспокоиться о настройке значения в двух местах.

Я считаю, что следующая логика, которую вы пытались достичь. Имейте в виду, что это не относится к пункту 7).

@echo off
setlocal
cd /d "c:\JPGfolder\"

:loop
set counter=0
for %%B in (*.jpg) do set /a counter+=1
echo File Count = %counter%

if %counter% EQU 4 (
  for /f "delims=|" %%I in ('DIR *.jpg /B /O:-D') DO (
    echo Newest File = "%%~fI"
    start "" /w "c:\programs\generate.exe" "%%~fI"
    del *.jpg
    ping -n 2 localhost >nul
    goto :break
  )
) else (
  echo File count <> 4
)
:break
goto :loop

Вышеприведенное может быть упрощено:

@echo off
setlocal
cd /d "c:\JPGfolder\"

:loop
set counter=0
for %%B in (*.jpg) do set /a counter+=1
echo File Count = %counter%

if %counter% EQU 4 (
  for /f "delims=|" %%I in ('DIR *.jpg /B /O:-D') DO (
    echo Newest File = "%%~fI"
    start "" /w "c:\programs\generate.exe" "%%~fI"
    del *.jpg
    ping -n 2 localhost >nul
    goto :loop
  )
)
echo File count <> 4
goto :loop

Но на самом деле, вы должны, вероятно, ввести задержку на каждой итерации, были ли 4 файла .jpg или нет.

@echo off
setlocal
cd /d "c:\JPGfolder\"

:loop
set counter=0
for %%B in (*.jpg) do set /a counter+=1
echo File Count = %counter%

if %counter% EQU 4 (
  for /f "delims=|" %%I in ('DIR *.jpg /B /O:-D') DO (
    echo Newest File = "%%~fI"
    start "" /w "c:\programs\generate.exe" "%%~fI"
    del *.jpg
    goto :break
  )
) else (
  echo File count <> 4
)
:break
ping -n 2 localhost >nul
goto :loop

Я не использовал бы какой-либо из вышеуказанного кода из-за точки 7). Я не могу решить это, потому что я не знаю, каковы ваши намерения.

ОБНОВИТЬ

Мне кажется, что вы отслеживаете папку для файлов изображений, и вы хотите обрабатывать каждую четвертую по какой-либо программе в хронологическом порядке. Все файлы удаляются после их получения. Я рекомендую перемещать файлы, а не удалять их, на случай, если что-то пойдет не так, и вы хотите восстановить некоторые другие изображения. Вы всегда можете вручную удалить сохраненные файлы в любой момент.

Ваш текущий алгоритм требует, чтобы пакетный скрипт читал и обрабатывал файлы быстрее, чем изображения, добавленные в папку, иначе вы рискуете потерять счетчик 4, и больше изображений не будет обработано (моя точка 7 сверху).

Ниже приведен новый алгоритм, который всегда работает независимо от того, как быстро добавляются изображения.

Вместо того, чтобы сбросить счетчик до 0 после каждого цикла, я позволяю счетчику расти неограниченно. Я использую modulo арифметику, чтобы определить, когда файл представляет кратное 4 (по модулю результат равен 0). Я обнаруживаю значение по модулю 0 путем преднамеренного повышения деления на нулевую ошибку, а || условно выполняет блок кода при ошибке.

@echo off
setlocal
cd /d "c:\JPGfolder"
md save 2>nul
set counter=0

:LOOP
for /f "delims=|" %%I in ('DIR *.jpg /B /O:-D') do (
  set /a "1/((counter+=1)%%4)" 2>nul || (
    echo Newest File = "%%~fI"
    start "" /w "c:\programs\generate.exe" "%%~fI"
  )
    move "%%I" save >nul
)
ping -n 2 localhost >nul
goto :LOOP

Ваш комментарий утверждает, что вы создаете коллаж из всех 4 изображений на каждой итерации. Я не вижу, как это работает, когда вы передаете только одно имя файла в файл generate.exe. Но если это действительно то, что происходит, тогда следующий альтернативный код должен работать:

@echo off
setlocal
cd /d "c:\JPGfolder"
2>nul (
  md save
  md working
  del working\*
)
set counter=0

:LOOP
for /f "delims=|" %%I in ('DIR *.jpg /B /O:-D') do (
  move "%%I" working >nul
  set /a "1/((counter+=1)%%4)" 2>nul || (
    echo Newest File = "%%~fI"
    start "" /w "c:\programs\generate.exe" "%%~dpIworking\%%~nxI"
    move working\* save >nul
  )
)
ping -n 2 localhost >nul
goto :LOOP

5
2017-09-15 20:58



Благодарим вас за подробный ответ, который имеет большой смысл. Ваше последнее предложение кода отлично работает. Что касается вашей точки 7: Файлы поступают с камеры и записываются по одному в папку. Поэтому я думаю, что не будет случая, когда в папке одновременно будет 5 файлов, но я продолжу тестирование, чтобы убедиться, что это может произойти. - mohawk
@mohawk - Создаете ли вы фильм, используя каждое 4-е изображение (отсортированное по хронологии) в папке? - dbenham
Нет, это фотоколлаж, состоящий из 4 последних снимков! - mohawk
@mohawk - Мне кажется, что я каждый четвертый снимок, а не последние 4. - dbenham
@mohawk - Как он использует все 4, когда вы передаете только один файл в качестве аргумента? - dbenham


В вашей логике сказано: если счетчик = 4, то для каждого jpg в папке запускается exe.

Установка счетчика на 0 внутри цикла, после того как вы уже определили его равным 4, не прекратит цикл.

У вас также есть неполный оператор IF, вызванный добавочной закрывающей скобкой (до: BREAK), которая возится с вашим заявлением ELSE.

Надеюсь, это поможет!


1
2017-09-15 19:26



Нет, GOTO :BREAK останавливает цикл. Утверждение IF не является неполным, оно просто прекращено досрочно. ) ELSE ( линии и ) строка просто игнорируется, потому что нет открытых блоков круглых скобок. Таким образом, все строки между ними выполняются безоговорочно (это особенность парсинга). - dbenham
@dbenham и последний goto: цикл запускает его снова. - LPChip
@LPChip - я имел в виду цикл FOR / F. Но теперь я вижу, что может возникнуть путаница в отношении того цикла, о котором мы говорим. Финал GOTO :LOOP явно выполняется безоговорочно, поэтому должно быть очевидно, что цикл GOTO никогда не заканчивается. - dbenham