19

I searched here, found someone using this

set is_dir=0
for %%i in ("%~1") do if exist "%%~si"\nul set is_dir=1

but didn't work, when %1==c:\this is a file with spaces.csproj, the test still success, which means it will still be treated as a folder!!!

anyone knows the answer, i guess this is a very common problem and Windows has existed for many many years, it should have a very simple solution....

aschipfl
  • 33,626
  • 12
  • 54
  • 99
aaron
  • 1,951
  • 3
  • 27
  • 41
  • 2
    Is your question really about ms-dos, or about a command prompt in windows? And which version? – wimh Dec 29 '11 at 12:23
  • my test environment are be both windows 7 x64 and windows xp, I did not try on other platforms. thanks. – aaron Dec 30 '11 at 03:49

6 Answers6

41

I know the if exist path\nul test for a folder used to work on MS-DOS. I don't know if it was broken with the introduction of long file names.

I knew that if exist "long path\nul" does not work on Windows batch. I did not realize until today that if exist path\nul works on Vista and beyond as long as path is in the short 8.3 form.

The original code appears to work on Vista. It seems like it should work on XP as well, but I believe the following XP bug is getting in the way: Batch parameter %~s1 gives incorrect 8.3 short name.

The original code does not need the FOR loop, it could simply use %~s1

Here is a variation that fully classifies a path as INVALID, FILE or FOLDER. It works on Vista, but does NOT work on XP because of the %~s1 bug. I'm not sure how it performs on MS-DOS.
EDIT 2015-12-08: There are a number of Windows situations where this fails

@echo off
if not exist "%~1" ( set "type=INVALID" ) else if exist %~s1\nul ( set "type=FOLDER" ) else ( set "type=FILE" )
@echo "%~1" = %type%

I believe this variation will work with nearly all versions of Microsoft batch, including MS-DOS and XP. (it obviously won't work on early versions of DOS that don't support PUSHD)

@echo off
if exist "%~1" (2>nul pushd "%~1" && (popd&set "type=FOLDER") || set "type=FILE" ) else set "type=INVALID"
echo "%~1" = %type%

UPDATE 2014-12-26

I'm pretty sure the following will work on all versions of Windows from XP onward, but I have only tested on Win 7.
Edit 2015-12-08: This can fail on network drives because the folder test can falsely report a file as a folder

@echo off
if exist %1\ (
  echo %1 is a folder
) else if exist %1 (
  echo %1 is a file
) else (
  echo %1 does not exist
)

UPDATE 2015-12-08

Finally - a test that truly should work on any Windows version from XP onward, including with network drives and UNC paths

for /f "tokens=1,2 delims=d" %%A in ("-%~a1") do if "%%B" neq "" (
  echo %1 is a folder
) else if "%%A" neq "-" (
  echo %1 is a file
) else (
  echo %1 does not exist
)

Note - This technique is intended to be used for a path without any wildcards (a single specific file or folder). If the provided path includes one or more wildcards, then it provides the result for the first file or folder that the file system encounters. Identical directory structures may give different sort order results depending on the underlying file system (FAT32, NTFS, etc.)

dbenham
  • 127,446
  • 28
  • 251
  • 390
  • @dbenham: Short note on the 2014 update, wouldn't it be a good idea to put the `%1\ ` and `%1` parts in quotes? – zb226 Dec 17 '15 at 12:26
  • 1
    @zb226 - No, adding additional quotes is not needed. The argument should already be quoted, else you couldn't have received it in the first place. Note that It does not hurt to have the `\` outside of any quotes. `"c:\path\"` and `"c:\path"\` are equivalent. If you really want to explicitly add your own quotes, then you must use `"%~1"` and `"%~1\"`. – dbenham Dec 17 '15 at 13:41
  • @dbenham: Ah now I get the rationale - since it's user-given input i.e. `%1`... I'm dealing with another situation at the moment where the filename under test is in a regular variable and then of course, quotes do matter. Anyway thanks for clearing that up! – zb226 Dec 17 '15 at 13:53
  • 1
    @zb226 - Sorry, backslash formatting issues messed up my comment. My note was to say that a path within quotes can have a backslash after the closing quote, and it works exactly the same as if the backslash was within the quotes. – dbenham Dec 17 '15 at 14:10
  • It's later; it could be a new situation. In today's Win10, the 2015-12-08 version reports `C:\dir\*.*` as a folder. For those who need this code to report this case as a file, here's my change: Before the 2015-12-08 code, add `set FilePath=%1 ^ if "%FilePath:~-3%" == "*.*" (echo %1 is a file) else`. (Maybe add some formatting I couldn't add here.) @dbenham: Great answer! – BaldEagle Dec 07 '18 at 15:21
  • I got feedback on my Dec 7 comment. Thanks. Maybe I've reported an interesting edge case for some. For some use cases (mine, for example), it's relevant that in a folder with both folders and files, `del *.*` deletes only files. For those use cases, this extension may be useful augmentation. May you have good results in choosing the tool useful to your problem. Thanks for the repeated tenacity of all prior contributors. This solution is working great for me. – BaldEagle Dec 13 '18 at 01:06
  • Last update with the for loop doesn't work on Win 10 18990 :-( Why is it inherent for the **exact same** batch file to give completely different results for completely different users?! The amount of time that I've wasted over the years just because of this stupidity is mind-boggling...and all while trying to **save** myself time by automating complex tasks! – Kenny83 Oct 31 '19 at 09:28
  • @BaldEagle - The technique is not intended for use with wildcards. See my note at the bottom of the updated answer. – dbenham Oct 31 '19 at 12:11
  • @Kenny83 - Does your path that gives inconsistent results include wildcards? If so, then that is the expected behavior. See the bottom note in my updated answer. – dbenham Oct 31 '19 at 12:13
  • @dbenham - Thanks for trying to help; I wasn't expecting a response :-) But no, no wildcards in play here. I simply tried your for loop example by running `name-of-bat "V:\Movies"` (which **is** a valid directory according to File Explorer) and got `"V:\Movies" is a file`. I suspect that this had something to do with the network drive not being mapped properly (as it works now), but still, I should've gotten the "doesn't exist" response in that case...weird! – Kenny83 Oct 31 '19 at 12:35
  • A suggestion: while the answer is great, the structure needs improvement. With all of this dates and edits/updates mix the valid point is almost indistinguishable in dark mode. In light a bit better. It will help if less valuable _**long super visible italic bold edits**_ will have _less visual weight_ than short but more valuable **updates**. – Andrii M4n0w4R Jun 18 '20 at 13:00
  • As far as I recall, `if exist "SomePath\*"` should even work for network paths… – aschipfl Nov 08 '22 at 21:59
9

I just tried in this way. Hope this helps.

@ECHO OFF
SET CURR_DIR=%CD%
SET IS_DIR=0
CD %1% 
IF "%ERRORLEVEL%"=="0" SET IS_DIR=1
CD %CURR_DIR%
ECHO IS DIRECTORY %IS_DIR% 

Output:

D:\Work\Stand alone Java classes>test.bat D:\Work\Training
IS DIRECTORY 1

D:\Work\Stand alone Java classes>test.bat D:\Work\Training\SRT.txt
The directory name is invalid.
IS DIRECTORY 0
Vaandu
  • 4,857
  • 12
  • 49
  • 75
  • 2
    Great, thanks! And I made it a litter shorter: `PUSHD %1 2>NUL && SET IS_DIR=1 || SET IS_DIR=0 & POPD` – aaron Dec 29 '11 at 15:03
2

The /ad option for "dir" command lists folders, /b option for bare. Assuming you have checks for the existence of file in place, use:

dir /ad /b ChangeThisToYourFilename 1> NUL 2> NUL
if %ERRORLEVEL% EQU 0 (
    echo is a folder
) else (
    echo is NOT a folder
)
SomethingDark
  • 13,229
  • 5
  • 50
  • 55
Arun
  • 2,493
  • 15
  • 12
  • 2
    Works if you change text to read 'is a folder' or 'is not a folder'. Interesting way of doing it. Not intuitive, but works because a folder always has the . and .. directories available within. A file never does. – dbenham Dec 31 '11 at 08:01
  • 1
    Simpler syntax - same solution: `dir /ad /b "somePath" 1>nul 2>nul && (echo is a folder) || (echo is not a folder)` – dbenham Dec 31 '11 at 08:01
  • if the folder contains a lot of sub-folders, this might take a while to execute? – aaron Dec 31 '11 at 09:10
1

For a 1 liner:

dir /a:d /b C:\Windows 2>&1 | findstr /i /n /c:"File Not Found">nul && (@echo. Im a file) || (@echo. Im a folder)

e.g. change C:\Windows to C:\Windows\Notepad.exe

-Sorry Arun, dbenham, didn't read yours! Same as..

MultiplyByZer0
  • 6,302
  • 3
  • 32
  • 48
fluoresc
  • 11
  • 2
1

Previously, I used the "\nul" method, but for a long time now, I have used "\*" to test if an existing filespec is a folder or a file. As far as I know, it works on all versions of Windows, from Windows 95 (and perhaps earlier versions) through all current Windows versions.

So, as with other methods, first test if the file exists. Then, to see if it's a "Folder", test it with: if exist "%fspec%\*":

if not exist "%fspec%"   goto :NotExistOrInvalid

rem "%fspec%" is "Valid" and is either a "Folder", or a "File".
if     exist "%fspec%\*" goto :IsValidAndIsAFolder

rem "%fspec%" is a "File" (a "Regular File" or a Shortcut/Link).
goto :IsValidAndIsAFile

For example:

set "fspec=XYZ:%perlpath%"
if not exist "%fspec%" echo "%fspec%": Invalid or not found && rem Invalid, goto :NotExistOrInvalid

set "fspec=%perlpath%"
if not exist "%fspec%" echo "%fspec%": Invalid or not found && rem goto :NotExistOrInvalid

rem "%fspec%" Is a "Valid" filespec and is either a "Folder", or a "File".
if exist "%fspec%\*" (echo "%fspec%" is a "Folder".) else echo "%fspec%" is a "File".

set "fspec=%perlpath%\perl.exe"
if not exist "%fspec%" echo "%fspec%": Invalid or not found && rem Invalid, goto :NotExistOrInvalid

rem "%fspec%" Is a "Valid" filespec and is either a "Folder", or a "File".
if exist "%fspec%\*" (echo "%fspec%" is a "Folder".) else echo "%fspec%" is a "File".

The output for this is:

"XYZ:F:\usr\perl\bin": Invalid or not found
"F:\usr\perl\bin" is a "Folder".
"F:\usr\perl\bin\perl.exe" is a "File".
Kevin Fegan
  • 1,292
  • 1
  • 16
  • 29
1

This solution combines the file attribute parameter extension (%~a1) with variable substring extraction (%variable:~0,1%):

@ECHO OFF

CALL :is_directory C:\Windows
CALL :is_directory C:\MinGW\share\doc\mingw-get\README
CALL :is_directory C:\$Recycle.Bin
CALL :is_directory "C:\Documents and Settings"
CALL :is_directory "%LOGONSERVER%\C$\Users\All Users"

GOTO :EOF

:is_directory
    SETLOCAL
    SET file_attribute=%~a1
    IF "%file_attribute:~0,1%"=="d" (
        ECHO %file_attribute% %1 is a directory
    ) ELSE (
        ECHO %file_attribute% %1 is NOT a directory
    )
    ENDLOCAL
    GOTO :EOF

Output:

d-------- C:\Windows is a directory
--a------ C:\MinGW\share\doc\mingw-get\README is NOT a directory
d--hs---- C:\$Recycle.Bin is a directory
d--hs---l "C:\Documents and Settings" is a directory
d--hs---l "\\MYCOMPUTER\C$\Users\All Users" is a directory
andronoid
  • 25
  • 6