【问题标题】:How to test if a file is a directory in a batch script?如何测试文件是否是批处理脚本中的目录?
【发布时间】:2008-09-26 11:57:24
【问题描述】:

有没有办法判断一个文件是否是一个目录?

我在变量中有文件名。在 Perl 中我可以这样做:

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

【问题讨论】:

标签: windows batch-file cmd


【解决方案1】:

这行得通:

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

孩子们,这在家里是安全的!

【讨论】:

  • 这似乎很好,它甚至可以正确处理空文件夹。更新:似乎也不需要'*',只需最后的'\'似乎就足以验证它是一个文件夹。
  • 太棒了,这个甚至工作 Directory Links!但只能使用*!!(也可以使用@GrantPeters)
  • 万一引号有问题,这也可以:如果存在 "%~1\" echo It's a directory
  • 此方法不适用于 Windows 10 20H2。
  • 太棒了!即使 UNC 路径和驱动器号映射到网络共享,也适用于我。以前我只使用 \ 它适用于本地文件和目录。
【解决方案2】:

最近使用与上述不同的方法失败了。很确定他们过去工作过,可能与此处的 dfs 有关。现在使用files attributes 并剪切第一个字符

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

【讨论】:

  • 这完全是最好的答案......如果您没有目标文件或目录的读取权限(这正是我需要的),它甚至可以工作。谢谢!
  • 此页面上三种可行的解决方案之一:isFile.bat 示例:pastebin.com/dmYKKa7M
  • 不知道为什么,但我的批处理文件没有将 %1 扩展为文件/文件夹完整路径。我必须使用%~f1。它将... 等路径扩展为真实路径。
  • 这是最好的方法,因为它使用文档化的功能,因此可以在未来的 Windows 版本中使用。例如,此页面上“赞”最多的方法在 Windows 10 20H2 中不起作用。但这一个有效。
【解决方案3】:

你可以这样做:

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

(注意 - 上面给出的示例是在批处理文件中工作的格式。要让它在命令行上工作,请将两个地方的 %% 替换为 %。)

【讨论】:

  • 你忘记了我认为的 d 标志
  • 这不起作用Directory Symbolic Links (Softlinks) or Junctions:路径包含目录链接的文件被误识别为目录。要重现,请键入: cmd <Ctrl>+<Shift>+<Enter> mklink /d LinkDir . cd LinkDir if exist regedt32.exe\nul echo File erroneously detected as Directory rd .
  • 它不起作用。但是,在末尾添加反斜杠确实对我有用。例如:如果存在 "%~1\" echo 它是一个目录
  • 这有效: FOR %%i IN (%1) DO IF EXIST %%~si* ECHO IS FOLDER
  • 这也不适用于 UNC 路径(即 \\server\share\...)。 @Vhaerun:请将您的“已接受答案”标记更新为 batchman61 的标记 - 这是此页面上唯一可靠的答案
【解决方案4】:

在我之前的产品之外,我发现这也有效:

if exist %1\ echo Directory

%1 周围不需要引号,因为调用者会提供它们。 与我一年前的回答相比,这节省了一个完整的按键;-)

【讨论】:

【解决方案5】:

这里有一个脚本,它使用 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

【讨论】:

【解决方案6】:

这很好用

if exist "%~1\" echo Directory

我们需要使用 %~1 从 %1 中删除引号,并在末尾添加反斜杠。然后再把thw整体放入qutes中。

【讨论】:

【解决方案7】:

CD 在指定目录不存在时返回EXIT_FAILURE。你得到了conditional processing symbols,所以你可以这样做。

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

:Error
CD %cd_backup%

【讨论】:

    【解决方案8】:

    @batchman61 方法的一种变体(检查 Directory 属性)。

    这次我使用了一个外部的“查找”命令。

    (哦,注意&amp;&amp; 技巧。这是为了避免冗长乏味的IF ERRORLEVEL 语法。)

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

    输出是:

    • 目录。
    • 目录符号链接或联结。
    • 损坏的 目录符号链接或联结。 (不尝试解析链接。)
    • 您没有读取权限的目录(例如“C:\System Volume Information”)

    【讨论】:

      【解决方案9】:

      NUL 技术似乎只适用于 8.3 兼容的文件名。

      (换句话说,`D:\Documents and Settings` 是“坏”,而 `D:\DOCUME~1` 是“好”)


      我认为当目录名称中有空格时使用“NUL”技术会有些困难,例如“文档和设置”。

      我正在使用 Windows XP Service Pack 2 并从 %SystemRoot%\system32\cmd.exe 启动 cmd 提示符

      以下是一些无效的示例以及对我有效的示例:

      (这些都是在交互式提示下“实时”完成的演示。我认为在尝试在脚本中调试它们之前,你应该让事情在那里工作。)

      这不起作用:

      D:\Documents and Settings&gt;if exist "D:\Documents and Settings\NUL" echo yes

      这不起作用:

      D:\Documents and Settings&gt;if exist D:\Documents and Settings\NUL echo yes

      这确实有效(对我来说):

      D:\Documents and Settings&gt;cd ..

      D:\&gt;REM get the short 8.3 name for the file

      D:\&gt;dir /x

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

      Directory of D:\
      09/25/2008 05:09 PM &lt;DIR&gt; 2008
      09/25/2008 05:14 PM &lt;DIR&gt; 200809~1.25 2008.09.25
      09/23/2008 03:44 PM &lt;DIR&gt; 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 &lt;DIR&gt; cygwin

      [[看这里!!!! ]]
      09/25/2008 08:34 AM &lt;DIR&gt; 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 &lt;DIR&gt; NATION~1 National Instruments Downloads
      10/12/2007 11:25 AM &lt;DIR&gt; NVIDIA
      05/13/2008 09:42 AM &lt;DIR&gt; Office10
      09/19/2008 11:08 AM &lt;DIR&gt; PROGRA~1 Program Files
      12/02/1999 02:54 PM 24,576 setx.exe
      09/15/2008 11:19 AM &lt;DIR&gt; TEMP
      02/14/2008 12:26 PM &lt;DIR&gt; tmp
      01/21/2008 07:05 PM &lt;DIR&gt; VXIPNP
      09/23/2008 12:15 PM &lt;DIR&gt; WINDOWS
      02/21/2008 03:49 PM &lt;DIR&gt; wx28
      02/29/2008 01:47 PM &lt;DIR&gt; WXWIDG~2 wxWidgets
      3 File(s) 510,704 bytes
      20 Dir(s) 238,250,901,504 bytes free

      D:\&gt;REM now use the \NUL test with the 8.3 name

      D:\&gt;if exist d:\docume~1\NUL echo yes

      yes

      这可行,但有点傻,因为点已经暗示我在一个目录中:

      D:\Documents and Settings&gt;if exist .\NUL echo yes

      【讨论】:

      • 问题似乎不在于长文件名,而在于名称中带有空格的目录。或者更确切地说,是变量名周围的引号阻止了 NUL 技巧的工作。我在答案中添加了一些代码,在测试之前将文件名转换为 8.3 名称。
      • NUL 技术不起作用Directory Symbolic Links (Softlinks) or Junctions:路径包含目录链接的文件被误识别为目录。要重现,请键入: cmd <Ctrl>+<Shift>+<Enter> mklink /d LinkDir . cd LinkDir if exist regedt32.exe\nul echo File erroneously detected as Directory rd .
      【解决方案10】:

      我用这个:

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

      【讨论】:

        【解决方案11】:

        这可以工作并且还可以处理带有空格的路径:

        dir "%DIR%" > NUL 2>&1
        
        if not errorlevel 1 (
            echo Directory exists.
        ) else (
            echo Directory does not exist.
        )
        

        在我看来,可能不是最有效但比其他解决方案更容易阅读。

        【讨论】:

        • 我喜欢你的回答是最简单的。由于某种原因,我不明白它突然停止工作,所以我发布了一个答案here
        • 替代方案:如果你可以cd 进入它...当然,请记住set cwd=%cd% 之前的当前目录以便稍后恢复...
        • 这会验证路径是否存在,但不区分文件或文件夹。
        【解决方案12】:

        一个非常简单的方法是检查孩子是否存在。

        如果一个孩子没有任何孩子,exist 命令将返回 false。

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

        如果你没有足够的访问权限,你可能会有一些误报(我没有测试过)。

        【讨论】:

        • 这绝对不行,尝试测试:如果存在 C:\Windows\explorer.exe\。 echo 是文件夹
        【解决方案13】:

        如果你可以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%
        

        【讨论】:

          【解决方案14】:

          基于 this article 标题为“批处理文件如何测试目录是否存在”,它“不完全可靠”。

          但我刚刚测试了这个:

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

          它似乎有效

          【讨论】:

          • 阅读文章“不可靠”意味着它在 Pathworks、Novell、DR-DOS 和 OS/2 上失败了,我怀疑这对大多数人来说是个问题。
          • 因此“不完全可靠”
          • 这不起作用Directory Symbolic Links (Softlinks) or Junctions:路径包含目录链接的文件被误识别为目录。要重现,请键入: cmd <Ctrl>+<Shift>+<Enter> mklink /d LinkDir . cd LinkDir if exist "regedt32.exe\NUL" echo File erroneously detected as Directory rd .
          【解决方案15】:

          这是我的解决方案:

          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
          

          【讨论】:

            【解决方案16】:

            我想发布我自己关于这个主题的函数脚本,希望有一天对某人有用。

            @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:存在,并且是一个文件。

            【讨论】:

              【解决方案17】:

              在 Windows 7 和 XP 下,我无法让它区分映射驱动器上的文件和目录。以下脚本:

              @echo 关闭 如果存在 c:\temp\data.csv 回显 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 something.txt 是一个文件 如果存在 k:\temp\something.txt\ echo something.txt 是一个目录 如果存在 k:\temp\something.txt\nul echo something.txt 是一个目录

              产生:

              data.csv 是一个文件 something.txt 是一个文件 something.txt 是一个目录 something.txt 是一个目录

              因此,请注意您的脚本是否可能被提供映射或 UNC 路径。下面的pushd解决方案似乎是最万无一失的。

              【讨论】:

              • 另见@batchman61 的解决方案,它通过检查属性来避免这个问题。
              【解决方案18】:

              这是我在 BATCH 文件中使用的代码

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

              ```

              【讨论】:

                【解决方案19】:

                这是我经过多次测试后的解决方案,包括 if exists、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 路径
                • 它适用于双引号完整路径或仅适用于目录名或文件名。
                • 即使您没有读取权限也可以使用
                • 它适用于目录链接(连接)。
                • 它适用于路径包含目录链接的文件。

                【讨论】:

                  【解决方案20】:

                  使用%%~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)

                  【讨论】:

                  • 不,当然%~s1 不会“猜测”/字符串操作短文件名,它会正确解析它。喜欢dir /x
                  【解决方案21】:

                  如果您的目标是只处理目录,那么这将很有用。

                  这取自https://ss64.com/nt/for_d.html

                  示例...列出文件夹 C:\Work\ 下名称以“User”开头的每个子文件夹:

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

                  FOR /DFOR /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-parameters]

                  如果 set 包含通配符,则指定匹配目录 名称而不是文件名。

                  【讨论】:

                  • 这是另一个问题的答案。如果给定的文件名是目录,它不适合这个关于检测的问题。
                  • 看到问题已经回答死了。这只是允许用户处理目录并跳过检查部分。
                  【解决方案22】:

                  我最近也在寻找这个,并且偶然发现了一个对我有用的解决方案,但我不知道它有什么限制(因为我还没有发现它们)。我相信这个答案本质上与上面 TechGuy 的答案相似,但我想增加另一个层次的可行性。无论哪种方式,我都非常成功地将参数扩展为完整的文件路径,我相信您必须使用 setlocal enableextensions 才能使其正常工作。

                  使用下面我可以判断文件是目录还是相反。这在很大程度上取决于用户实际需要什么。如果您更喜欢在您的工作中使用搜索 errorlevel&amp;&amp;|| 的构造,您当然可以这样做。有时,errorlevel 的 if 构造可以为您提供更多的灵活性,因为您不必使用有时会破坏您的环境条件的 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
                  

                  【讨论】:

                    【解决方案23】:

                    我们不能用这个来测试吗:

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

                    这似乎对我有用。

                    【讨论】:

                    • 这不适用于包含点的文件夹。事实证明扩展是猜测的,没有解决。
                    • 如果文件夹名称是myfolder.fld怎么办?
                    猜你喜欢
                    • 2011-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2018-12-08
                    • 1970-01-01
                    • 2013-04-11
                    • 1970-01-01
                    • 2011-04-24
                    相关资源
                    最近更新 更多