376
votes

How can I iterate over each file in a directory using a for loop?

And how could I tell if a certain entry is a directory or if it's just a file?

17
assuming you meant the default windows shell, I've retagged your post for a little bit of more clarityDavid Schmitt
Please also specify what version of Windows you are using.jop
This should be split into two separate questions as they are independent from each other.julealgon

17 Answers

537
votes

This lists all the files (and only the files) in the current directory:

for /r %i in (*) do echo %i

Also if you run that command in a batch file you need to double the % signs.

for /r %%i in (*) do echo %%i

(thanks @agnul)

229
votes

Iterate through...

  • ...files in current dir: for %f in (.\*) do @echo %f
  • ...subdirs in current dir: for /D %s in (.\*) do @echo %s
  • ...files in current and all subdirs: for /R %f in (.\*) do @echo %f
  • ...subdirs in current and all subdirs: for /R /D %s in (.\*) do @echo %s

Unfortunately I did not find any way to iterate over files and subdirs at the same time.

Just use cygwin with its bash for much more functionality.

Apart from this: Did you notice, that the buildin help of MS Windows is a great resource for descriptions of cmd's command line syntax?

Also have a look here: http://technet.microsoft.com/en-us/library/bb490890.aspx

94
votes

To iterate over each file a for loop will work:

for %%f in (directory\path\*) do ( something_here )

In my case I also wanted the file content, name, etc.

This lead to a few issues and I thought my use case might help. Here is a loop that reads info from each '.txt' file in a directory and allows you do do something with it (setx for instance).

@ECHO OFF
setlocal enabledelayedexpansion
for %%f in (directory\path\*.txt) do (
  set /p val=<%%f
  echo "fullname: %%f"
  echo "name: %%~nf"
  echo "contents: !val!"
)

*Limitation: val<=%%f will only get the first line of the file.

64
votes

There is a subtle difference between running FOR from the command line and from a batch file. In a batch file, you need to put two % characters in front of each variable reference.

From a command line:

FOR %i IN (*) DO ECHO %i

From a batch file:

FOR %%i IN (*) DO ECHO %%i
44
votes

This for-loop will list all files in a directory.

pushd somedir
for /f "delims=" %%f in ('dir /b /a-d-h-s') do echo %%f
popd

"delims=" is useful to show long filenames with spaces in it....

'/b" show only names, not size dates etc..

Some things to know about dir's /a argument.

  • Any use of "/a" would list everything, including hidden and system attributes.
  • "/ad" would only show subdirectories, including hidden and system ones.
  • "/a-d" argument eliminates content with 'D'irectory attribute.
  • "/a-d-h-s" will show everything, but entries with 'D'irectory, 'H'idden 'S'ystem attribute.

If you use this on the commandline, remove a "%".

Hope this helps.

12
votes

%1 refers to the first argument passed in and can't be used in an iterator.

Try this:

@echo off
for %%i in (*.*) do echo %%i
7
votes

I had trouble getting jop's answer to work with an absolute path until I found this reference: https://ss64.com/nt/for_r.html

The following example loops through all files in a directory given by the absolute path.

For /R C:\absoulte\path\ %%G IN (*.*) do (
  Echo %%G
)
5
votes
for %1 in (*.*) do echo %1

Try "HELP FOR" in cmd for a full guide

This is the guide for XP commands. http://www.ss64.com/nt/

5
votes

To iterate through all files and folders you can use

for /F "delims=" %%a in ('dir /b /s') do echo %%a

To iterate through all folders only not with files, then you can use

for /F "delims=" %%a in ('dir /a:d /b /s') do echo %%a

Where /s will give all results throughout the directory tree in unlimited depth. You can skip /s if you want to iterate through the content of that folder not their sub folder

Implementing search in iteration

To iterate through a particular named files and folders you can search for the name and iterate using for loop

for /F "delims=" %%a in ('dir "file or folder name" /b /s') do echo %%a

To iterate through a particular named folders/directories and not files, then use /AD in the same command

for /F "delims=" %%a in ('dir "folder name" /b /AD /s') do echo %%a
3
votes

The following code creates a file Named "AllFilesInCurrentDirectorylist.txt" in the current Directory, which contains the list of all files (Only Files) in the current Directory. Check it out

dir /b /a-d > AllFilesInCurrentDirectorylist.txt
3
votes

It could also use the forfiles command:

forfiles /s 

and also check if it is a directory

forfiles /p c:\ /s /m *.* /c "cmd /c if @isdir==true echo @file is a directory"
3
votes

Here's my go with comments in the code.

I'm just brushing up by biatch skills so forgive any blatant errors.

I tried to write an all in one solution as best I can with a little modification where the user requires it.

Some important notes: Just change the variable recursive to FALSE if you only want the root directories files and folders processed. Otherwise, it goes through all folders and files.

C&C most welcome...

@echo off
title %~nx0
chcp 65001 >NUL
set "dir=c:\users\%username%\desktop"
::
:: Recursive Loop routine - First Written by Ste on - 2020.01.24 - Rev 1
::
setlocal EnableDelayedExpansion
rem THIS IS A RECURSIVE SOLUTION [ALBEIT IF YOU CHANGE THE RECURSIVE TO FALSE, NO]
rem By removing the /s switch from the first loop if you want to loop through
rem the base folder only.
set recursive=TRUE
if %recursive% equ TRUE ( set recursive=/s ) else ( set recursive= )
endlocal & set recursive=%recursive%
cd /d %dir%
echo Directory %cd%
for %%F in ("*") do (echo    → %%F)                                 %= Loop through the current directory. =%
for /f "delims==" %%D in ('dir "%dir%" /ad /b %recursive%') do (    %= Loop through the sub-directories only if the recursive variable is TRUE. =%
  echo Directory %%D
  echo %recursive% | find "/s" >NUL 2>NUL && (
    pushd %%D
    cd /d %%D
    for /f "delims==" %%F in ('dir "*" /b') do (                      %= Then loop through each pushd' folder and work on the files and folders =%
      echo %%~aF | find /v "d" >NUL 2>NUL && (                        %= This will weed out the directories by checking their attributes for the lack of 'd' with the /v switch therefore you can now work on the files only. =%
      rem You can do stuff to your files here.
      rem Below are some examples of the info you can get by expanding the %%F variable.
      rem Uncomment one at a time to see the results.
      echo    → %%~F           &rem expands %%F removing any surrounding quotes (")
      rem echo    → %%~dF          &rem expands %%F to a drive letter only
      rem echo    → %%~fF          &rem expands %%F to a fully qualified path name
      rem echo    → %%~pF          &rem expands %%A to a path only
      rem echo    → %%~nF          &rem expands %%F to a file name only
      rem echo    → %%~xF          &rem expands %%F to a file extension only
      rem echo    → %%~sF          &rem expanded path contains short names only
      rem echo    → %%~aF          &rem expands %%F to file attributes of file
      rem echo    → %%~tF          &rem expands %%F to date/time of file
      rem echo    → %%~zF          &rem expands %%F to size of file
      rem echo    → %%~dpF         &rem expands %%F to a drive letter and path only
      rem echo    → %%~nxF         &rem expands %%F to a file name and extension only
      rem echo    → %%~fsF         &rem expands %%F to a full path name with short names only
      rem echo    → %%~dp$dir:F    &rem searches the directories listed in the 'dir' environment variable and expands %%F to the fully qualified name of the first one found. If the environment variable name is not defined or the file is not found by the search, then this modifier expands to the empty string
      rem echo    → %%~ftzaF       &rem expands %%F to a DIR like output line
      )
      )
    popd
    )
  )
echo/ & pause & cls
2
votes

I would use vbscript (Windows Scripting Host), because in batch I'm sure you cannot tell that a name is a file or a directory.

In vbs, it can be something like this:

Dim fileSystemObject
Set fileSystemObject = CreateObject("Scripting.FileSystemObject")

Dim mainFolder
Set mainFolder = fileSystemObject.GetFolder(myFolder)

Dim files
Set files = mainFolder.Files

For Each file in files
...
Next

Dim subFolders
Set subFolders = mainFolder.SubFolders

For Each folder in subFolders
...
Next

Check FileSystemObject on MSDN.

2
votes

I use the xcopy command with the /L option to get the file names. So if you want to get either a directory or all the files in the subdirectory you could do something like this:

for /f "delims=" %%a IN ('xcopy "D:\*.pdf" c:\ /l') do echo %%a

I just use the c:\ as the destination because it always exists on windows systems and it is not copying so it does not matter. if you want the subdirectories too just use /s option on the end. You can also use the other switches of xcopy if you need them for other reasons.

2
votes

Try this to test if a file is a directory:

FOR /F "delims=" %I IN ('DIR /B /AD "filename" 2^>^&1 ^>NUL') DO IF "%I" == "File Not Found" ECHO Not a directory

This only will tell you whether a file is NOT a directory, which will also be true if the file doesn't exist, so be sure to check for that first if you need to. The carets (^) are used to escape the redirect symbols and the file listing output is redirected to NUL to prevent it from being displayed, while the DIR listing's error output is redirected to the output so you can test against DIR's message "File Not Found".

2
votes

try this:

::Example directory
set SetupDir=C:\Users

::Loop in the folder with "/r" to search in recursive folders, %%f being a loop ::variable 
for /r "%SetupDir%" %%f in (*.msi *.exe) do set /a counter+=1

echo there are %counter% files in your folder

it counts .msi and .exe files in your directory (and in the sub directory). So it also makes the difference between folders and files as executables.

Just add an extension (.pptx .docx ..) if you need to filter other files in the loop

1
votes

In my case I had to delete all the files and folders underneath a temp folder. So this is how I ended up doing it. I had to run two loops one for file and one for folders. If files or folders have spaces in their names then you have to use " "

cd %USERPROFILE%\AppData\Local\Temp\
rem files only
for /r %%a in (*) do (
echo deleting file "%%a" ...
if exist "%%a" del /s /q "%%a"
)
rem folders only
for /D %%a in (*) do (
echo deleting folder "%%a" ...
if exist "%%a" rmdir /s /q "%%a"
)