Как проверить, является ли файл каталогом в пакетном сценарии?

Есть ли способ узнать, является ли файл каталогом?

У меня есть имя файла в переменной. В Perl я могу сделать это:

if(-d $var) { print "it's a directory\n" }

person Vhaerun    schedule 26.09.2008    source источник


Ответы (23)


Вы можете сделать это так:

IF EXIST %VAR%\NUL ECHO It's a directory

Однако это работает только для каталогов без пробелов в именах. Когда вы добавляете кавычки вокруг переменной для обработки пробелов, она перестает работать. Чтобы обрабатывать каталоги с пробелами, преобразуйте имя файла в короткий формат 8.3 следующим образом:

FOR %%i IN (%VAR%) DO IF EXIST %%~si\NUL ECHO It's a directory

%%~si преобразует %%i в имя файла 8.3. Чтобы увидеть все другие трюки, которые вы можете выполнять с FOR переменными, введите HELP FOR в командной строке.

(Примечание: приведенный выше пример предназначен для работы в пакетном файле. Чтобы он работал в командной строке, замените %% на % в обоих местах.)

person Dave Webb    schedule 26.09.2008
comment
ты забыл флаг d я думаю - person RomanM; 26.09.2008
comment
У меня все работало нормально, а какой флаг D? Роман - D: в вашем ответе есть ссылка на диск D: на вашей машине. Ваерун, на что у вас был установлен VAR, когда вы пытались это сделать? - person Dave Webb; 26.09.2008
comment
C:\sdf›если существует файл, который существует\nul @echo ничего не будет отображать ‹-- попробуйте, см. здесь --› pastebin.com/raw.php?i=u8trFYLf - person barlop; 07.04.2012
comment
ЭТО НЕ РАБОТАЕТ с символическими ссылками каталога (программными ссылками) или соединениями.: файлы, путь которых содержит ссылку на каталог, ошибочно распознаются как каталог. Для воспроизведения введите: ‹Win›cmd - person Aaron Thoma; 23.06.2012
comment
Это не работает. Однако добавление обратной косой черты в конце сработало для меня. Например: если существует %~1\ эхо Это каталог - person MarioVilas; 06.06.2013
comment
Мариовилас прав... В Windows 7 по крайней мере \NUL не работает. а просто\работает! Спасибо! - person Dss; 07.12.2013
comment
Это работает: FOR %%i IN (%1) DO IF EXIST %%~si* ECHO IS FOLDER - person Jakob Sternberg; 03.01.2014
comment
Это также не работает для путей UNC (например, \\server\share\...). @Vhaerun: Пожалуйста, обновите отметку о принятом ответе на отметку от batchman61 - это единственный надежный ответ на этой странице. - person WinTakeAll; 16.04.2016
comment
Проверка с помощью NUL не работает в ReactOS, но проверка с помощью %var%\* работает. - person Ken Jackson; 11.08.2017

Это работает:

if exist %1\* echo Directory

Работает с именами каталогов, которые содержат пробелы:

C:\>if exist "c:\Program Files\*" echo Directory
Directory

Обратите внимание, что кавычки необходимы, если каталог содержит пробелы:

C:\>if exist c:\Program Files\* echo Directory

Также может быть выражено как:

C:\>SET D="C:\Program Files"
C:\>if exist %D%\* echo Directory
Directory

Это безопасно, чтобы попробовать дома, дети!

person Gerard    schedule 23.09.2009
comment
Кажется, это хорошо, он даже правильно обрабатывает пустую папку. Обновление: похоже, что «*» также не требуется, достаточно «\» в конце, чтобы убедиться, что это папка. - person Grant Peters; 27.01.2011
comment
Отлично, это даже работает с Ссылки на каталоги! Но только с *!! (Также @GrantPeters) - person Aaron Thoma; 23.06.2012
comment
На всякий случай, если кавычки - проблема, это тоже работает: если существует %~1\ echo Это каталог - person MarioVilas; 06.06.2013
comment
Этот метод не работает в Windows 10 20H2. - person CoolCmd; 25.04.2021

Недавно потерпел неудачу с различными подходами из вышеперечисленного. Совершенно уверен, что они работали в прошлом, возможно, здесь это связано с dfs. Теперь используйте атрибуты файлов и вырежьте первый символ

@echo off
SETLOCAL ENABLEEXTENSIONS
set ATTR=%~a1
set DIRATTR=%ATTR:~0,1%
if /I "%DIRATTR%"=="d" echo %1 is a folder
:EOF
person batchman61    schedule 16.09.2010
comment
Это лучший ответ здесь ... Он работает даже в том случае, если у вас нет прав на чтение целевого файла или каталога (это именно то, что мне нужно). Спасибо! - person ewall; 22.06.2011
comment
Одно из трех решений на этой странице, которое работает: пример isFile.bat: pastebin.com/dmYKKa7M - person Jakob Sternberg; 03.01.2014
comment
Не знаю почему, но мой командный файл не расширяет %1 до полного пути к файлу/папке. Я должен использовать %~f1. Он расширяет пути, такие как . и .., до реального пути. - person WesternGun; 09.02.2021
comment
Это лучший способ, поскольку он использует задокументированные функции и, следовательно, будет работать в будущих версиях Windows. Например, способ с наибольшим количеством лайков на этой странице не работает в Windows 10 20H2. Но этот работает. - person CoolCmd; 25.04.2021

В дополнение к моему предыдущему предложению, я считаю, что это также работает:

if exist %1\ echo Directory

Кавычки вокруг %1 не нужны, потому что вызывающая сторона предоставит их. Это экономит одно нажатие клавиши по сравнению с моим ответом год назад ;-)

person Gerard    schedule 02.10.2010
comment
ЭТО НЕ РАБОТАЕТ с символическими ссылками каталога (программными ссылками) или соединениями.: файлы, путь которых содержит ссылку на каталог, ошибочно распознаются как каталог. Для воспроизведения введите: ‹Win›cmd - person Aaron Thoma; 23.06.2012

Вот сценарий, который использует FOR для создания полного пути, а затем pushd для проверки, является ли путь каталогом. Обратите внимание, как это работает для путей с пробелами, а также для сетевых путей.

@echo off
if [%1]==[] goto usage

for /f "delims=" %%i in ("%~1") do set MYPATH="%%~fi"
pushd %MYPATH% 2>nul
if errorlevel 1 goto notdir
goto isdir

:notdir
echo not a directory
goto exit

:isdir
popd
echo is a directory
goto exit

:usage
echo Usage:  %0 DIRECTORY_TO_TEST

:exit

Пример вывода с сохраненным выше как «isdir.bat»:

C:\>isdir c:\Windows\system32
is a directory

C:\>isdir c:\Windows\system32\wow32.dll
not a directory

C:\>isdir c:\notadir
not a directory

C:\>isdir "C:\Documents and Settings"
is a directory

C:\>isdir \
is a directory

C:\>isdir \\ninja\SharedDocs\cpu-z
is a directory

C:\>isdir \\ninja\SharedDocs\cpu-z\cpuz.ini
not a directory
person indiv    schedule 27.09.2008
comment
Это работает даже с символическими ссылками каталога (программными ссылками) и соединениями. (В отличие от методов \NUL и ``.) - person Aaron Thoma; 29.06.2012
comment
@accolade - каковы методы ``? - person Kevin Fegan; 03.07.2016
comment
@KevinFegan (Похоже, StackExchange изменил синтаксический анализ форматирования встроенного кода `…`.) « `` » должно было быть « \ ». Я имел в виду подход добавления обратной косой черты в конце имени файла, например. предлагается здесь: stackoverflow.com/questions/138981/ - person Aaron Thoma; 05.12.2016

Это отлично работает

if exist "%~1\" echo Directory

нам нужно использовать %~1, чтобы удалить кавычки из %1 и добавить обратную косую черту в конце. Затем снова положите их целиком в котлеты.

person Aziz    schedule 27.09.2011
comment
ЭТО НЕ РАБОТАЕТ с символическими ссылками каталога (программными ссылками) или соединениями.: файлы, путь которых содержит ссылку на каталог, ошибочно распознаются как каталог. Для воспроизведения введите: ‹Win›cmd - person Aaron Thoma; 23.06.2012

Вариант подхода @batchman61 (проверка атрибута Directory).

На этот раз я использую внешнюю команду «найти».

(О, и обратите внимание на трюк &&. Это сделано для того, чтобы избежать длинного скучного синтаксиса IF ERRORLEVEL.)

@ECHO OFF
SETLOCAL EnableExtensions
ECHO.%~a1 | find "d" >NUL 2>NUL && (
    ECHO %1 is a directory
)

Выходы да вкл.:

  • Каталоги.
  • Символические ссылки или соединения каталогов.
  • Неработающие символические ссылки или соединения каталогов. (Не пытается разрешать ссылки.)
  • Каталоги, на чтение которых у вас нет разрешения (например, «C:\System Volume Information»)
person Explorer09    schedule 10.03.2015

Техника NUL работает только с именами файлов, совместимыми с 8.3.

(Другими словами, «D:\Documents and Settings» — «плохо», а «D:\DOCUME~1» — «хорошо»).


Я думаю, что есть некоторые трудности с использованием метода «NUL», когда в имени каталога есть ПРОБЕЛЫ, такие как «Документы и настройки».

Я использую пакет обновления 2 для Windows XP и запускаю командную строку из %SystemRoot%\system32\cmd.exe

Вот несколько примеров того, что НЕ работает и что РАБОТАЕТ для меня:

(Все эти демонстрации выполняются «вживую» в интерактивной подсказке. Я полагаю, что вы должны заставить все работать там, прежде чем пытаться отлаживать их в сценарии.)

Это НЕ сработало:

D:\Documents and Settings>if exist "D:\Documents and Settings\NUL" echo yes

Это НЕ сработало:

D:\Documents and Settings>if exist D:\Documents and Settings\NUL echo yes

Это работает (для меня):

D:\Documents and Settings>cd ..

D:\>REM get the short 8.3 name for the file

D:\>dir /x

Volume in drive D has no label. Volume Serial Number is 34BE-F9C9

Directory of D:\
09/25/2008 05:09 PM <DIR> 2008
09/25/2008 05:14 PM <DIR> 200809~1.25 2008.09.25
09/23/2008 03:44 PM <DIR> BOOST_~3 boost_repo_working_copy
09/02/2008 02:13 PM 486,128 CHROME~1.EXE ChromeSetup.exe
02/14/2008 12:32 PM <DIR> cygwin

[[Смотри сюда !!!! ]]
09/25/2008 08:34 AM <DIR> DOCUME~1 Documents and Settings

09/11/2008 01:57 PM 0 EMPTY_~1.TXT empty_testcopy_file.txt
01/21/2008 06:58 PM <DIR> NATION~1 National Instruments Downloads
10/12/2007 11:25 AM <DIR> NVIDIA
05/13/2008 09:42 AM <DIR> Office10
09/19/2008 11:08 AM <DIR> PROGRA~1 Program Files
12/02/1999 02:54 PM 24,576 setx.exe
09/15/2008 11:19 AM <DIR> TEMP
02/14/2008 12:26 PM <DIR> tmp
01/21/2008 07:05 PM <DIR> VXIPNP
09/23/2008 12:15 PM <DIR> WINDOWS
02/21/2008 03:49 PM <DIR> wx28
02/29/2008 01:47 PM <DIR> WXWIDG~2 wxWidgets
3 File(s) 510,704 bytes
20 Dir(s) 238,250,901,504 bytes free

D:\>REM now use the \NUL test with the 8.3 name

D:\>if exist d:\docume~1\NUL echo yes

yes

Это работает, но немного глупо, потому что точка уже означает, что я нахожусь в каталоге:

D:\Documents and Settings>if exist .\NUL echo yes

person pestophagous    schedule 26.09.2008
comment
Проблема заключается не в длинных именах файлов, а в каталогах с пробелами в именах. Вернее, именно кавычки вокруг имени переменной мешают работе трюка с NUL. Я добавил в свой ответ код, который перед тестированием преобразует имена файлов в имена 8.3. - person Dave Webb; 29.09.2008
comment
Техника NUL НЕ РАБОТАЕТ с символическими ссылками каталога (программными ссылками). или Junctions: файлы, путь которых содержит ссылку на каталог, ошибочно распознаются как каталог. Для воспроизведения введите: ‹Win›cmd - person Aaron Thoma; 23.06.2012

Я использую это:

if not [%1] == [] (
  pushd %~dpn1 2> nul
  if errorlevel == 1 pushd %~dp1
)
person Kimae    schedule 08.09.2010

Это работает, а также обрабатывает пути с пробелами в них:

dir "%DIR%" > NUL 2>&1

if not errorlevel 1 (
    echo Directory exists.
) else (
    echo Directory does not exist.
)

Вероятно, не самое эффективное, но, на мой взгляд, более легкое для чтения, чем другие решения.

person Samuel    schedule 10.02.2015
comment
Ваш ответ мне понравился как самый простой. По какой-то причине я не понимаю, что он внезапно перестал работать, поэтому я разместил ответ здесь. - person Chris Murphy; 28.06.2015
comment
Альтернативный подход: если вы можете cd войти в него... конечно, запомните свой текущий каталог до set cwd=%cd%, чтобы восстановить его позже... - person Frank Nocke; 25.10.2015
comment
Это подтверждает, что путь существует, но не различает файл или папку. - person dbenham; 25.12.2015

CD возвращает EXIT_FAILURE, если указанный каталог не существует. И у вас есть символы условной обработки, так что вы можете сделать для этого, как показано ниже.

SET cd_backup=%cd%
(CD "%~1" && CD %cd_backup%) || GOTO Error

:Error
CD %cd_backup%
person Константин Ван    schedule 29.07.2018

Очень простой способ — проверить, существует ли потомок.

Если у дочернего элемента нет ни одного дочернего элемента, команда exist вернет значение false.

IF EXIST %1\. (
  echo %1 is a folder
) else (
  echo %1 is a file
)

У вас может быть ложный отрицательный результат, если у вас нет достаточных прав доступа (я не проверял).

person Cedric    schedule 26.07.2012
comment
это не работает абсолютно, попробуйте проверить: если существует C:\Windows\explorer.exe\. эхо это папка - person indalive; 10.10.2017

Если вы можете cd войти в него, это каталог:

set cwd=%cd%

cd /D "%1" 2> nul
@IF %errorlevel%==0 GOTO end

cd /D "%~dp1"
@echo This is a file.

@goto end2
:end
@echo This is a directory
:end2

@REM restore prior directory
@cd %cwd%
person Frank Nocke    schedule 25.10.2015

Основано на этой статье под названием "Как можно пакетный файл проверяет наличие каталога», это «не совсем надежно».

НО я только что проверил это:

@echo off
IF EXIST %1\NUL goto print
ECHO not dir
pause
exit
:print
ECHO It's a directory
pause

и вроде работает

person RomanM    schedule 26.09.2008
comment
Чтение статьи ненадежно означает, что она не работает в Pathworks, Novell, DR-DOS и OS/2, что, я сомневаюсь, станет проблемой для большинства людей. - person Dave Webb; 26.09.2008
comment
значит не совсем надежный - person RomanM; 26.09.2008
comment
ЭТО НЕ РАБОТАЕТ с символическими ссылками каталога (программными ссылками) или соединениями.: файлы, путь которых содержит ссылку на каталог, ошибочно распознаются как каталог. Для воспроизведения введите: ‹Win›cmd - person Aaron Thoma; 24.06.2012

Вот мое решение:

REM make sure ERRORLEVEL is 0
TYPE NUL

REM try to PUSHD into the path (store current dir and switch to another one)
PUSHD "insert path here..." >NUL 2>&1

REM if ERRORLEVEL is still 0, it's most definitely a directory
IF %ERRORLEVEL% EQU 0 command...

REM if needed/wanted, go back to previous directory
POPD
person user966939    schedule 07.06.2013

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

@pushd %~dp1
@if not exist "%~nx1" (
        popd
        exit /b 0
) else (
        if exist "%~nx1\*" (
                popd
                exit /b 1
        ) else (
                popd
                exit /b 3
        )
)

Этот пакетный скрипт проверяет, существует ли файл/папка и является ли это файлом или папкой.

Использование:

script.bat "ПУТЬ"

Код выхода:

0: файл/папка не существует.

1: существует, и это папка.

3: существует, и это файл.

person M. Jamal    schedule 20.09.2017

В Windows 7 и XP я не могу заставить его различать файлы и каталоги на подключенных дисках. Следующий скрипт:

@echo off
if exist c:\temp\data.csv echo data.csv is a file
if exist c:\temp\data.csv\ echo data.csv is a directory
if exist c:\temp\data.csv\nul echo data.csv is a directory
if exist k:\temp\nonexistent.txt echo nonexistent.txt is a file
if exist k:\temp\something.txt echo something.txt is a file
if exist k:\temp\something.txt\ echo something.txt is a directory
if exist k:\temp\something.txt\nul echo something.txt is a directory

производит:

data.csv is a file
something.txt is a file
something.txt is a directory
something.txt is a directory

Так что будьте осторожны, если ваш сценарий может быть загружен сопоставленным или UNC-путем. Приведенное ниже решение pushd кажется наиболее надежным.

person user117529    schedule 12.07.2011
comment
См. также решение от @batchman61, которое позволяет избежать этой проблемы, проверяя атрибуты. - person jdigital; 19.04.2012

Это код, который я использую в своих пакетных файлах.

```
@echo off
set param=%~1
set tempfile=__temp__.txt
dir /b/ad > %tempfile%
set isfolder=false
for /f "delims=" %%i in (temp.txt) do if /i  "%%i"=="%param%" set isfolder=true
del %tempfile%
echo %isfolder%
if %isfolder%==true echo %param% is a directory

```

person gialloporpora    schedule 12.07.2012

Вот мое решение после многих тестов, если есть, pushd, dir/AD и т. д.

@echo off
cd /d C:\
for /f "delims=" %%I in ('dir /a /ogn /b') do (
    call :isdir "%%I"
    if errorlevel 1 (echo F: %%~fI) else echo D: %%~fI
)
cmd/k

:isdir
echo.%~a1 | findstr /b "d" >nul
exit /b %errorlevel%

:: Errorlevel
:: 0 = folder
:: 1 = file or item not found
  • Работает с файлами без расширения
  • Он работает с папками с именем folder.ext
  • Он работает с путем UNC
  • Он работает с полным путем в двойных кавычках или только с именем каталога или только с именем файла.
  • Это работает, даже если у вас нет прав на чтение
  • Он работает со ссылками на каталоги (соединениями).
  • Он работает с файлами, путь которых содержит ссылку на каталог.
person Amr Ali    schedule 24.11.2014

Одна проблема с использованием метода %%~si\NUL заключается в том, что есть вероятность, что он угадает неправильно. Возможно, имя файла будет сокращено до неправильного файла. Я не думаю, что %%~si разрешает имя файла 8.3, но угадывает его, но использует манипуляции со строками для сокращения пути к файлу. Я считаю, что если у вас одинаковые пути к файлам, это может не сработать.

Альтернативный метод:

dir /AD %F% 2>&1 | findstr /C:"Not Found">NUL:&&(goto IsFile)||(goto IsDir)

:IsFile
  echo %F% is a file
  goto done

:IsDir
  echo %F% is a directory
  goto done

:done

Вы можете заменить (goto IsFile)||(goto IsDir) другими пакетными командами:
(echo Is a File)||(echo is a Directory)

person TechGuy    schedule 07.09.2010
comment
Нет, конечно, %~s1 не угадывает/манипулирует строкой с коротким именем файла, он правильно его разрешает. Как 2_ - person Aaron Thoma; 24.06.2012

Если ваша цель состоит в том, чтобы обрабатывать только каталоги, то это будет полезно.

Это взято из https://ss64.com/nt/for_d.html.

Пример... Перечислите все подпапки под папкой C:\Work\, имя которой начинается с «Пользователь»:

CD \Work
FOR /D /r %%G in ("User*") DO Echo We found

FOR /D or FOR /D /R

@echo off
cd /d "C:\your directory here"
for /d /r %%A in ("*") do echo We found a folder: %%~nxA
pause

Удалите /r, чтобы углубиться только в одну папку. Переключатель /r является рекурсивным и недокументированным в приведенной ниже команде.

Справка for /d взята из команды for /?

FOR /D %variable IN (set) DO command [параметры команды]

Если набор содержит подстановочные знаки, то указывает соответствие именам каталогов, а не именам файлов.

person Ste    schedule 24.01.2020
comment
Это ответ на другой вопрос. Это не подходит для ЭТОГО вопроса об обнаружении, если данное имя файла является каталогом. - person jeb; 24.01.2020
comment
Учитывая, что на вопрос ответили смертью. Это просто позволяет пользователю обрабатывать каталоги и пропускать часть проверки. - person Ste; 24.01.2020

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

Используя ниже, я могу определить, является ли файл каталогом или наоборот. Многое зависит от того, что на самом деле нужно пользователю. Если вы предпочитаете работать с конструкцией, ищущей errorlevel по сравнению с && и || в своей работе, вы, конечно, можете это сделать. Иногда конструкция if для errorlevel может дать вам немного больше гибкости, поскольку вам не нужно использовать команду GOTO, которая иногда может нарушить условия вашей среды.

@Echo Off
setlocal enableextensions

Dir /b /a:D "%~f1" && Echo Arg1 is a Folder || Echo Arg1 is NOT a Folder

Dir /b /a:-D "%~f1" && Echo Arg1 is a File || Echo Arg1 is NOT a File

pause

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

@Echo Off
setlocal enableextensions


Dir /b /s "C:\SomeFolderIAmCombing\*" >"%~dp0SomeFiletogoThroughlater.txt"

For /f "Usebackq Delims=" %%a in ("%~dp0SomeFiletogoThroughlater.txt") do (
  Call:DetectDir "%%a"
)

REM Do some stuff after parsing through Files/Directories if needed.  
REM GOTO:EOF below is used to skip all the subroutines below.

REM Using ' CALL:DetectDir "%%a" ' with the for loop keeps the for 
REM loop environment running in the background while still parsing the given file
REM in a clean environment where GOTO and other commmands do not need Variable Expansion.

GOTO:EOF

:DetectDir [File or Folder being checked]

REM Checks if Arg1 is a Directory.  If yes, go to Dir coding. If not, go to File coding.
Dir /b /a:D "%~f1" && Echo Arg1 is a Folder & GOTO:IsDir || Echo Arg1 is NOT a Folder & GOTO:IsFile

REM Checks if Arg1 is NOT a Directory.  If Yes, go to File coding.  If not, go to Dir coding
Dir /b /a:-D "%~f1" && Echo Arg1 is a File & GOTO:IsFile || Echo Arg1 is NOT a File & GOTO:IsDir

:IsDir
  REM Do your stuff to the Folder
GOTO:EOF

:IsFile
  REM do your stuff to the File
GOTO:EOF
person David Barber    schedule 09.06.2021

Разве мы не можем просто проверить это:

IF [%~x1] == [] ECHO Directory

Кажется, это работает для меня.

person Lucien Baron    schedule 15.04.2013
comment
Это не будет работать с папками, содержащими точку. Получается расширение угадывается, а не разрешается. - person Jakob Sternberg; 03.01.2014
comment
что если имя папки myfolder.fld? - person phuclv; 30.11.2016