{"id":6953,"date":"2012-08-03T07:00:00","date_gmt":"2012-08-03T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2012\/08\/03\/forfiles-for-your-fancier-batch-file-enumeration-needs\/"},"modified":"2012-08-03T07:00:00","modified_gmt":"2012-08-03T07:00:00","slug":"forfiles-for-your-fancier-batch-file-enumeration-needs","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20120803-00\/?p=6953","title":{"rendered":"FORFILES, for your fancier batch file enumeration needs"},"content":{"rendered":"<p>\nCrack open open the champagne:\nBatch File Week is finally over!\n<\/p>\n<p>\nVariations on the\n<code>for \/f %%i in ('dir \/b ...')<\/code>\nwill let you repeat an operation on the contents of a directory,\npossibly even recursively if you add the <code>\/s<\/code> option,\nwith some basic attribute-level filtering if you add the\n<code>\/a<\/code> or <\/code>\/a-<\/code> flags.\n<\/p>\n<p>\nFor your fancy recursive file operations,\nthere&#8217;s a tool called\n<code>FORFILES<\/code> which iterates through the contents of a\ndirectory (recursively if requested),\nexecuting a command on each item it finds.\nIt also has additional filtering capability,\nlike selecting files based on their last-modified time.\nFor example,\nyou could copy all files in the current directory which were\nmodified today:\n<\/p>\n<pre>\nforfiles \/D +0 \/c \"cmd \/c copy @file \\\\server\\today\"\n<\/pre>\n<p>\nUnfortuantely, the <code>\/D<\/code> option is not as flexible\nas one might like.\nFor example, while it can pick files modified today,\nit can&#8217;t pick files modified in the last week,\nbecause the relative-date-picker knows only how to pick\n<i>files modified on or before a date in the past<\/i>\nor\n<i>files modified on or after a date in the future<\/i>.\n(Who the heck wants to operate on files modified in the future?\nExcept perhaps the Microsoft Research folks who are working\non that time machine.)\n<\/p>\n<p>\nYou can type <code>FORFILES \/?<\/code> for more information on what\nyou can do (and by seeing what&#8217;s omitted, what you can&#8217;t do).\n<\/p>\n<p>\nIf the command you want to execute is rather long,\nyou can offload it back into the batch file being executed:\n<\/p>\n<pre>\n@echo off\nif \"%1\"==\"\/callback\" goto callback\nforfiles \/D +0 \/c \"cmd \/c call \"%~f0\" \/callback @isdir @file @fsize\"\ngoto :eof\n:callback\nrem %2 = @isdir\nrem %3 = @file\nrem %4 = @fsize\nif %2==TRUE echo Skipping directory %3.&amp;goto :eof\necho Copying file %3 to \\\\server\\today (%4 bytes)\n<\/pre>\n<p>\nOne gotcha here is that since each command runs in a sub-shell,\nit can read environment variables, but any modifications it makes\nto environment variables will be lost since the command is modifying\nonly its local environment variables.\nA workaround for this is to use <code>FORFILES<\/code> to select\nthe data to operate on,\nbut use <code>FOR<\/code> to actually perform the operation.\nSince <code>FOR<\/code> runs inside the main command interpreter,\nit can modify environment variables.\n<\/p>\n<pre>\nset TOTALSIZE=0\nfor \/f %%i in ('forfiles \/d +0 \/c \"cmd \/c if @isdir==FALSE echo @fsize\"') <a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2008\/08\/06\/8835317.aspx\">^<\/a>\ndo set \/a TOTALSIZE=TOTALSIZE + %%i\n<\/pre>\n<p>\nHere, we use <code>FORFILES<\/code> to enumerate all the files\n(not directories)\nmodified today\nand print their sizes.\nWe wrap this inside a <code>FOR<\/code> which reads the sizes\nand adds them up.\n<\/p>\n<p>\nIf the operation you want to perform on each file is complex,\nyou can of course offload it into a\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2012\/08\/02\/10334559.aspx\">\nsubroutine call<\/a>.\n<\/p>\n<pre>\nfor \/f %%i ^\nin ('forfiles \/d +0 \/c \"cmd \/c if @isdir==FALSE echo @fsize\"') ^\ndo call :subroutine %%i\n<\/pre>\n<p>\nI&#8217;m cheating here because I know that <code>@fsize<\/code> doesn&#8217;t\ncontain spaces.\nIf you are processing file names, then you need to be more careful.\n<\/p>\n<pre>\nfor \/f \"tokens=*\" %%i ^\nin ('forfiles \/d +0 \/c \"cmd \/c if @isdir==FALSE echo @fname\"') ^\ndo call :subroutine %%i\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Crack open open the champagne: Batch File Week is finally over! Variations on the for \/f %%i in (&#8216;dir \/b &#8230;&#8217;) will let you repeat an operation on the contents of a directory, possibly even recursively if you add the \/s option, with some basic attribute-level filtering if you add the \/a or \/a- flags. [&hellip;]<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-6953","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Crack open open the champagne: Batch File Week is finally over! Variations on the for \/f %%i in (&#8216;dir \/b &#8230;&#8217;) will let you repeat an operation on the contents of a directory, possibly even recursively if you add the \/s option, with some basic attribute-level filtering if you add the \/a or \/a- flags. [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/6953","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=6953"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/6953\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=6953"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=6953"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=6953"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}