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

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

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

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

24 ответа

Решение

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

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 в командной строке.

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

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

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

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

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

@echo off
SETLOCAL ENABLEEXTENSIONS
set ATTR=%~a1
set DIRATTR=%ATTR:~0,1%
if /I "%DIRATTR%"=="d" echo %1 is a folder
:EOF

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

if exist %1\ echo Directory

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

Вот скрипт, который использует 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

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

if exist "%~1\" echo Directory

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

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

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

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

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

Выходы да на:

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

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

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

:Error
CD %cd_backup%

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

(Другими словами, `D:\Documents and Settings` -" плохо ", а`D:\DOCUME~1` - "хорошо")


Я думаю, что есть некоторая сложность в использовании метода "NUL", когда в имени каталога есть ПРОСТРАНСТВА, такие как "Документы и настройки".

Я использую Windows XP с пакетом обновления 2 и запускаю команду cmd из%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

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

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

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

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

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

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

Если ты можешь 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%

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

Если у ребенка нет ребенка, exist команда вернет false.

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

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

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

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

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

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

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

и похоже на работу

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

@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: существует, и это файл.

Вот мое решение после многих тестов, если они существуют, 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 path
  • Он работает с полным путем в двойных кавычках или только с именем или именем файла.
  • Это работает, даже если у вас нет прав на чтение
  • Работает со справочными ссылками (соединениями).
  • Он работает с файлами, путь которых содержит ссылку на каталог.

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

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

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

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

FOR /D или 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 % переменная IN (set) Команда DO [команда-параметры]

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

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

@ эхо выключено
если существует c: \ temp \ data.csv echo data.csv - это файл
если существует c: \ temp \ data.csv \ echo data.csv - это каталог
если существует c:\temp\data.csv\nul echo data.csv - это каталог
если существует k:\temp\nonexistent.txt echo nonexistent.txt - это файл
если существует k:\temp\something.txt echo что-то.txt является файлом
если существует, то k:\temp\something.txt\ echo something.txt - это каталог
если существует k:\temp\something.txt\nul echo something.txt - это каталог

производит:

data.csv - это файл
что-то.txt это файл
что-то.txt является каталогом
что-то.txt является каталогом

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

Хорошо... трюк 'nul' не работает, если вы используете кавычки в именах, которые составляют большинство файлов с длинными именами или пробелами.

Например,

if exist "C:\nul" echo Directory

ничего не делает, но

if exist C:\nul echo Directory

работает.

Я наконец придумал это, которое, казалось, работало для всех случаев:

for /f %%i in ('DIR /A:D /B %~dp1 ^| findstr /X /c:"%~nx1"') do echo Directory

или если вы можете быть уверены, что выполняете все требования для "nul", решение:

if exist %~sf1\nul echo Directory

Поместите их в командный файл, например, "test.bat" и выполните "test.bat MyFile".

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

```
@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

```

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

Используя ниже, я могу сказать, является ли файл каталогом или наоборот. Во многом это зависит от того, что на самом деле нужно пользователю. Если вы предпочитаете работать с конструкцией, ищущей vs && а также ||в своей работе вы, конечно, можете это делать. Иногда конструкция 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

Одна проблема с использованием %%~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)

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

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

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

Другие вопросы по тегам