Como testar se um arquivo é um diretório em um script em lotes?

Existe alguma maneira de descobrir se um arquivo é um diretório?

Eu tenho o nome do arquivo em uma variável. Em Perl eu posso fazer isso:

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

Você pode fazer assim:

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

No entanto, isso só funciona para diretórios sem espaços em seus nomes. Quando você adiciona cotas em volta da variável para manipular os espaços, ela pára de funcionar. Para manipular diretórios com espaços, converta o nome do arquivo em formato 8.3 curto da seguinte maneira:

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

O %%~si converte %%i em um nome de arquivo 8.3. Para ver todos os outros truques que você pode executar com variables FOR , insira HELP FOR em um prompt de comando.

(Nota – o exemplo dado acima está no formato para trabalhar em um arquivo de lote. Para fazê-lo funcionar na linha de comando, substitua o %% por % em ambos os lugares.)

Isso funciona:

 if exist %1\* echo Directory 

Funciona com nomes de diretório que contêm espaços:

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

Observe que as aspas são necessárias se o diretório contiver espaços:

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

Também pode ser expresso como:

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

Isso é seguro para tentar em casa, crianças!

Recentemente falhou com diferentes abordagens do acima. Tenho certeza que eles trabalharam no passado, talvez relacionado a dfs aqui. Agora usando os atributos de arquivos e corte primeiro caractere

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

Além da minha oferta anterior, acho que isso também funciona:

 if exist %1\ echo Directory 

Nenhuma citação em torno de% 1 é necessária porque o chamador as fornecerá. Isso salva uma keystroke inteira sobre a minha resposta de um ano atrás 😉

Aqui está um script que usa FOR para construir um caminho totalmente qualificado e, em seguida, pushd para testar se o caminho é um diretório. Observe como funciona para caminhos com espaços, bem como caminhos de rede.

 @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 

Exemplo de saída com o acima salvo como “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 

Isso funciona perfeitamente

 if exist "%~1\" echo Directory 

precisamos usar% ~ 1 para remover aspas de% 1 e adicionar uma barra invertida no final. Em seguida, coloque tudo em qutes novamente.

A técnica NUL parece funcionar apenas em nomes de arquivo compatíveis com 8.3.

(Em outras palavras, `D: \ Documents and Settings` é” bad “e` D: \ DOCUME ~ 1` é “bom”)


Eu acho que há alguma dificuldade em usar a técnica “NUL” quando há espaços no nome do diretório, como “Documents and Settings”.

Estou usando o service pack 2 do Windows XP e inicio o prompt do cmd em% SystemRoot% \ system32 \ cmd.exe

Aqui estão alguns exemplos do que não funcionou e o que funciona para mim:

(Essas são todas as demonstrações feitas “ao vivo” em um prompt interativo. Eu acho que você deve fazer com que as coisas funcionem lá antes de tentar depurá-las em um script.)

Isso não funcionou:

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

Isso não funcionou:

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

Isso funciona (para mim):

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

2008
09/25/2008 05:14 PM 200809~1.25 2008.09.25
09/23/2008 03:44 PM 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 cygwin

[[Veja bem aqui !!!! ]]
09/25/2008 08:34 AM

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

NATION~1 National Instruments Downloads
10/12/2007 11:25 AM NVIDIA
05/13/2008 09:42 AM Office10
09/19/2008 11:08 AM PROGRA~1 Program Files
12/02/1999 02:54 PM 24,576 setx.exe
09/15/2008 11:19 AM TEMP
02/14/2008 12:26 PM tmp
01/21/2008 07:05 PM VXIPNP
09/23/2008 12:15 PM WINDOWS
02/21/2008 03:49 PM wx28
02/29/2008 01:47 PM 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

Isso funciona, mas é meio bobo, porque o ponto já implica que eu estou em um diretório:

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

Isso funciona e também lida com caminhos com espaços:

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

Provavelmente não é o mais eficiente, mas mais fácil de ler do que as outras soluções na minha opinião.

Uma variação da abordagem do @ batchman61 (verificando o atributo Directory).

Desta vez eu uso um comando externo ‘find’.

(Ah, e observe o truque && . Isso é para evitar a syntax IF ERRORLEVEL longa e chata.)

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

Saídas sim em:

  • Diretórios.
  • Vínculos ou junções simbólicas do diretório.
  • Ligações ou junções simbólicas do diretório quebrado . (Não tenta resolver links.)
  • Diretórios nos quais você não possui permissão de leitura (por exemplo, “C: \ System Volume Information”)

Eu uso isso:

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

Uma maneira muito simples é verificar se a criança existe.

Se um filho não tiver filho, o comando exist retornará falso.

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

Você pode ter algum falso negativo se não tiver access suficiente (não testei).

Com base neste artigo intitulado “Como pode um arquivo de lote testar a existência de um diretório”, ele “não é totalmente confiável”.

MAS eu acabei de testar isso:

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

E parece que funciona

Aqui está minha solução:

 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 

Se você pode cd dentro dele, é um diretório:

 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% 

Eu gostaria de postar meu próprio script de function sobre esse assunto para ser útil para alguém um dia.

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

Este script em lote verifica se o arquivo / pasta existe e se é um arquivo ou uma pasta.

Uso:

script.bat “PATH”

Sair do (s) código (s):

0: arquivo / pasta não existe.

1: existe e é uma pasta.

3: existe e é um arquivo.

No Windows 7 e XP, não consigo dizer para arquivos vs. dirs em unidades mapeadas. O script a seguir:

 @echo off
 se existir c: \ temp \ data.csv echo data.csv é um arquivo
 se existir c: \ temp \ data.csv \ echo data.csv é um diretório
 se existir c: \ temp \ data.csv \ nul echo data.csv é um diretório
 se existir k: \ temp \ nonexistent.txt echo nonexistent.txt é um arquivo
 se existir k: \ temp \ algo.txt echo algo.txt é um arquivo
 se existir k: \ temp \ algo.txt \ echo algo.txt é um diretório
 se existir k: \ temp \ algo.txt \ num echo algo.txt é um diretório

produz:

 data.csv é um arquivo
 algo.txt é um arquivo
 algo.txt é um diretório
 algo.txt é um diretório

Portanto, tenha cuidado se seu script pode ser alimentado com um caminho mapeado ou UNC. A solução pushd abaixo parece ser a mais infalível.

Este é o código que eu uso nos meus arquivos 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 

“ `

Ok … o truque ‘nul’ não funciona se você usar aspas em nomes, o que representa a maioria dos arquivos com nomes de arquivos longos ou espaços.

Por exemplo,

 if exist "C:\nul" echo Directory 

não faz nada, mas

 if exist C:\nul echo Directory 

trabalho.

Eu finalmente pensei nisso, o que pareceu funcionar em todos os casos:

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

ou se você puder garantir que atende a todos os requisitos para ‘nul’, uma solução é:

 if exist %~sf1\nul echo Directory 

Coloque-os em um arquivo de lote como ‘test.bat’ e faça ‘test.bat MyFile’.

Aqui está a minha solução depois de muitos testes com if, pushd, dir / AD, etc …

 @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 
  • Funciona com arquivos sem extensão
  • Ele funciona com pastas denominadas folder.ext
  • Funciona com o caminho UNC
  • Ele funciona com o caminho completo com aspas duplas ou apenas com o nome do dirname ou com o nome do arquivo.
  • Funciona mesmo que você não tenha permissions de leitura
  • Ele funciona com links de diretório (Junções).
  • Trabalha com arquivos cujo caminho contém um link de diretório.

Um problema com o uso do método %%~si\NUL é que existe a chance de ele adivinhar errado. É possível ter um nome de arquivo reduzido ao arquivo errado. Eu não acho que %%~si resolva o nome do arquivo 8.3, mas adivinhe, mas usando a manipulação de strings para encurtar o caminho do arquivo. Eu acredito que se você tiver caminhos de arquivo semelhantes, pode não funcionar.

Um método alternativo:

 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 

Você pode replace (goto IsFile)||(goto IsDir) com outros comandos em lote:
(echo Is a File)||(echo is a Directory)

CD retorna um EXIT_FAILURE quando o diretório especificado não existe. E você tem símbolos de processamento condicionais , então você poderia fazer como abaixo para isso.

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

Não podemos apenas testar com isso:

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

Parece funcionar para mim.