Пакетная обработка — файл-призрак проходит проверку «Если не существует»

Мой код

У меня есть прямой код ниже:

  1. Проверяет, существует ли файл в моем каталоге
  2. Запускает цикл for для получения первого имени файла
  3. Делает вещи на основе имени файла
  4. Удаляет файл
  5. Проверяет, существуют ли какие-либо другие файлы в каталоге (если да, повторите, если нет, идите дальше)

    :MYLOOP
    IF NOT EXIST "%mypath%\*.*" GOTO nofile
    FOR %%F IN ("%mypath%\*.*") DO (
        set filenameWithExt=%%~nxF
        set filename=%%~nF
        set filepath=%%~pF
        )
    do other filename specific tasks
    
    del "%mypath%\%filenameWithExt%"
    
    IF NOT EXIST "%mypath%\*.*" GOTO nofile
    
    GOTO MYLOOP
    
    :nofile
    

Моя проблема

Я неоднократно использовал этот код, и он работал как шарм, но в моем последнем использовании он выглядел как обнаружение файла-призрака. Когда в каталоге нет ФАЙЛОВ (есть одна архивная ПАПКА), проверка if not exist из шага 1 выше каким-то образом все еще проходит. В результате код set в цикле for приводит к следующему результату:

Система не может найти указанный файл.

И затем кажется, что он пытается удалить мой каталог, говоря:

\\mypath*, Вы уверены (да/нет)?

Затем мне приходится вручную завершать автоматический пакет.

Мой вопрос

Почему он проходит проверку if not exist, а не переходит к :nofile?

Как я могу объяснить этот «призрачный» файл (или если он обнаруживает архивную папку - как еще я могу его игнорировать)?


person TMY    schedule 16.06.2017    source источник
comment
Итак, вы хотите проверить, есть ли какой-либо файл в %mypath%, прежде чем продолжить?   -  person dcg    schedule 16.06.2017
comment
Я бы посоветовал вам, если вы собираетесь работать с файлами внутри %mypath%, делать это путем повторения вывода dir /b "%mypath%\*.*".   -  person dcg    schedule 16.06.2017


Ответы (2)


Тест if exist ищет все в каталоге.

Я бы реструктурировал ваш код:

:MYLOOP
set "found1="
FOR %%F IN ("%mypath%\*.*") DO (
    set filenameWithExt=%%~nxF
    set filename=%%~nF
    set filepath=%%~pF
    set "found1=Y"
    )
if not defined found1 goto nofile

do other filename specific tasks

del "%mypath%\%filenameWithExt%"
GOTO MYLOOP

:nofile

Если for не находит файлов, found1 останется неопределенным, поэтому мы переходим к метке :nofile, иначе у нас есть файл для обработки. Удалив файл, просто вернитесь в начало, снимите флажок и повторите...

person Magoo    schedule 16.06.2017
comment
еще не реализовал это, но логика кажется мне совершенно разумной - очевидно, глубоко в этот момент, что я не мог видеть лес за деревьями. Спасибо! - person TMY; 16.06.2017

Ядро Windows и, следовательно, интерпретатор команд Windows интерпретируют шаблон подстановочных знаков *.* как *, что означает любой файл или папку. Использование подстановочного знака *.* не означает, что должен быть файл (или папка) с точкой в ​​имени.

По этой причине использование условия IF NOT EXIST "%mypath%\*.*" аналогично использованию IF NOT EXIST "%mypath%\*".

IF EXIST "%mypath%\*" часто используется в пакетных файлах для проверки того, что %mypath% указывает папку, а не файл, потому что это условие проверяет, существует ли папка %mypath%. Условие true, если эта папка существует, независимо от количества файлов и папок в этой папке.

Таким образом, условие в верхней части вашего пакетного файла не проверяет, нет ли хотя бы 1 файла в папке %mypath%, оно проверяет, не существует ли эта папка вообще.

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

@echo off
for /F "delims=" %%I in ('dir /A-D /B /ON "%mypath%\*" 2^>nul') do call :ProcessFile "%mypath%\%%I"
goto :EOF

:ProcessFile
set "FilenNmeWithExt=%~nx1"
set "FileName=%~n1"
set "FilePath=%~p1"
rem do other filename specific tasks
del "%~1"
goto :EOF

Команда FOR выполняет командную строку

dir /A-D /B /ON "%mypath%\*" 2>nul

в отдельном командном процессе в фоновом режиме и фиксирует выходные данные DIR, записанные для обработки STDOUT.

DIR выводит сообщение об ошибке для обработки STDERR, если каталог вообще не существует или не содержит файлов. Это сообщение об ошибке подавляется перенаправлением на устройство NUL с помощью 2>nul. Оператор перенаправления > должен быть экранирован здесь символом вставки ^, чтобы он сначала интерпретировался интерпретатором команд Windows как литеральный символ при анализе всей командной строки FOR, иначе результатом будет синтаксическая ошибка.

Опция /A-D означает, что DIR должен выводить все записи каталога, НЕ имеющие установленного атрибута каталога, то есть только файлы, а не папки. /B изменяет вывод DIR в пустой формат, что означает только имена файлов без каких-либо дополнительных данных. /ON приводит к упорядочению списка по имени файла до того, как DIR выведет весь список. Здесь эта опция не очень нужна.

FOR теперь обрабатывает захваченный вывод DIR. Поэтому не имеет значения, удаляются ли файлы из этого каталога во время работы FOR. FOR обрабатывает исходный список как вывод DIR.

Для каждого имени файла, выводимого DIR, выполняется подпрограмма ProcessFile, которая аналогична вызову другого пакетного файла с этим именем. Подпрограмме передается имя файла с путем к нему. DIR выводит только имя файла без пути, если не использовать дополнительно /S для получения списка всех имен файлов в указанном каталоге и всех его подкаталогах.

Команда goto :EOF после цикла FOR требуется, чтобы избежать провала подпрограммы после обработки всех имен файлов, выводимых DIR.

Команда goto :EOF после подпрограммы не требуется, если строка выше является последней строкой командного файла. Но в целом хорошей практикой является всегда заканчивать подпрограмму goto :EOF в случае добавления дополнительных командных строк, таких как другая подпрограмма ниже. Для интерпретатора команд Windows не имеет значения, где в файле находится подпрограмма, начинающаяся с ее метки.

person Mofi    schedule 16.06.2017
comment
Вот это да! Спасибо за подробный ответ @mofi! Я уже принял ответ Магу, но хотел быстро ответить с благодарностью. Определенно есть несколько лакомых кусочков, которые я буду иметь в виду на будущее. - person TMY; 16.06.2017