dos下遍历目录和文件的代码(主要利用for命令)
程序员文章站
2022-03-22 09:38:51
===== 文件夹结构 ============================================= d:\test ---a folder 1 |-----...
===== 文件夹结构 =============================================
d:\test
---a folder 1
|-----a file 1.txt
|-----a file 2.txt
|-----a file 3.txt
---b folder 2
|-----b file 1.txt
|-----b file 2.txt
|-----b file 3.txt
|---b folder 3
|-----b sub file 1.txt
|-----b sub file 2.txt
|-----b sub file 3.txt
@echo off
set work_path=d:\test
d:
cd %work_path%
for /r %%s in (.,*) do (
echo %%s
)
pause
结果
d:\test\.
d:\test\a folder 1\.
d:\test\a folder 1\a file 1.txt
d:\test\a folder 1\a file 2.txt
d:\test\a folder 1\a file 3.txt
d:\test\b folder 2\.
d:\test\b folder 2\b file 1.txt
d:\test\b folder 2\b file 2.txt
d:\test\b folder 2\b file 3.txt
d:\test\b folder 2\b folder 3\.
d:\test\b folder 2\b folder 3\b sub file 1.txt
d:\test\b folder 2\b folder 3\b sub file 2.txt
d:\test\b folder 2\b folder 3\b sub file 3.txt
@echo off
set work_path=d:\test
d:
cd %work_path%
for /r %%s in (.) do (
echo %%s
)
pause
结果
d:\test\.
d:\test\a folder 1\.
d:\test\a folder 1\a file 1.txt
d:\test\a folder 1\a file 2.txt
d:\test\a folder 1\a file 3.txt
d:\test\b folder 2\.
d:\test\b folder 2\b file 1.txt
d:\test\b folder 2\b file 2.txt
d:\test\b folder 2\b file 3.txt
d:\test\b folder 2\b folder 3\.
d:\test\b folder 2\b folder 3\b sub file 1.txt
d:\test\b folder 2\b folder 3\b sub file 2.txt
d:\test\b folder 2\b folder 3\b sub file 3.txt
那么
for /r %%s in (.,*) do (
echo %%s
)
和
for /r %%s in (.) do (
echo %%s
)
的区别是什么呢?
在有cd %work_path% 的时候,这两个命令执行的结果是一样的,就像我们上面举的例子。但是
for /r %%s in (.,*) do (
echo %%s
)
的批处理中没有cd %work_path% ,那么显示的将是这个批处理文件所在文件夹下面的遍历结果。
@echo off
for /r "d:\test" %%s in (.) do (
echo %%s
)
pause
结果
d:\test\.
d:\test\a folder 1\.
d:\test\b folder 2\.
d:\test\b folder 2\b folder 3\.
@echo off
for /r "d:\test" %%s in (.,*) do (
echo %%s
)
pause
结果
d:\test\.
d:\test\a folder 1\.
d:\test\a folder 1\a file 1.txt
d:\test\a folder 1\a file 2.txt
d:\test\a folder 1\a file 3.txt
d:\test\b folder 2\.
d:\test\b folder 2\b file 1.txt
d:\test\b folder 2\b file 2.txt
d:\test\b folder 2\b file 3.txt
d:\test\b folder 2\b folder 3\.
d:\test\b folder 2\b folder 3\b sub file 1.txt
d:\test\b folder 2\b folder 3\b sub file 2.txt
d:\test\b folder 2\b folder 3\b sub file 3.txt
这样的话看出来区别了吧。
再看一个=================================
@echo off
for /r "d:\test" %%s in (*) do (
echo %%s
)
pause
结果
d:\test\a folder 1\a file 1.txt
d:\test\a folder 1\a file 2.txt
d:\test\a folder 1\a file 3.txt
d:\test\b folder 2\b file 1.txt
d:\test\b folder 2\b file 2.txt
d:\test\b folder 2\b file 3.txt
d:\test\b folder 2\b folder 3\b sub file 1.txt
d:\test\b folder 2\b folder 3\b sub file 2.txt
d:\test\b folder 2\b folder 3\b sub file 3.txt
就是只显示了文件
visitf.bat - 对指定路径指定文件进行遍历的程序
:: visitf.bat - 对指定路径指定文件进行遍历的程序
:: 第一参数为要遍历的文件(支持通配符),第二参数为要遍历的路径(缺省为c盘根)
@echo off
:main
if [%1]==[] if not exist goto end
:init
if exist if exist goto loop
set file=%1
set base=%2
if [%2]==[] set base=c:
dir %base%\%file% /s /a /b >
echo e 100 ''set file='' >
echo w >>
echo q >>
:loop
fc nul /n | find " 1:" > setfile.bat
if errorlevel 1 goto restore
debug setfile.bat nul
call setfile.bat
echo visiting the file: %file%
:: user specified visit code replace this line
find "%file%" /v
copy > nul
goto loop
:restore
if exist del
if exist del
if exist del
if exist setfile.bat del setfile.bat
:end
visitd.bat - 对指定路径指定目录进行遍历的程序
:: visitd.bat - 对指定路径指定目录进行遍历的程序
:: 第一参数为要遍历的目录(支持通配符),第二参数为要遍历的路径(缺省为c盘根)
@echo off
:main
if [%1]==[] if not exist goto end
:init
if exist if exist goto loop
set dir=%1
set base=%2
if [%2]==[] set base=c:
dir %base%\%dir% /s /ad /b >
echo e 100 'set dir=' >
echo w >>
echo q >>
:loop
fc nul /n | find " 1:" > setdir.bat
if errorlevel 1 goto restore
debug setdir.bat nul
call setdir.bat
echo visiting the dir: %dir%
:: user specified visit code replace this line
find "%dir%" /v
copy > nul
goto loop
:restore
if exist del
if exist del
if exist del
if exist setdir.bat del setdir.bat
:end
visitl.bat - 对指定文件列表中的文件进行遍历的程序
:: visitl.bat - 对指定文件列表中的文件进行遍历的程序
:: 参数为要遍历的文件列表
@echo off
:main
if [%1]==[] if not exist goto end
:init
set filelist=%1
if [%1]==[] set filelist=
if not exist %filelist% goto end
copy %filelist% > nul
if exist goto loop
echo e 100 'set file=' >
echo w >>
echo q >>
:loop
fc nul /n | find " 1:" > setfile.bat
if errorlevel 1 goto restore
debug setfile.bat nul
call setfile.bat
echo visiting the file: %file%
:: user specified visit code replace this line
find "%file%" /v
copy > nul
goto loop
:restore
if exist del
if exist del
if exist del
if exist setfile.bat del setfile.bat
:end
visiti.bat - 对指定路径指定dir信息的文件进行遍历操作的的程序
:: visiti.bat - 对指定路径指定dir信息的文件进行遍历操作的的程序
:: 第一参数为指定的dir信息项,第二参数为要遍历的路径(缺省为当前路径)
:: 注意:dir信息项可以是文件名,扩展名,日期,时间等dir命令提供的目录信息项
:: 可以同时使用多项,但必须加一对引号,参数格式也须严格符合dir的信息格式
@echo off
:main
if [%1]==[] goto end
:init
if exist if exist goto loop
set info=%1
set base=%2
if [%2]==[] set base=.
dir %base%\. /s /a /b >
echo e 100 ''''set file='''' >
echo w >>
echo q >>
:loop
fc nul /n | find " 1:" > setfile.bat
if errorlevel 1 goto restore
debug setfile.bat nul
call setfile.bat
dir "%file%" | find %info% > nul
if not errorlevel 1 echo visit file: "%file%"
:: if not errorlevel 1
find "%file%" /v
:: "%file%" 参数决定了所匹配的子目录下的所有文件和目录均不会再次匹配
copy > nul
goto loop
:restore
if exist del
if exist del
if exist del
if exist setfile.bat del setfile.bat
set info=
set file=
set base=
:end
visit.bat - 文件遍历批处理程序
:: visit.bat - 文件遍历批处理程序
:: will sort - 10/17/2004 - v2
::
:: 程序用途:
:: 对指定文件集/目录集/文件列表执行指定操作
::
:: 命令行说明:
:: 1. visit 文件集/目录集 [参数]
:: 对文件集/目录集执行指定操作
:: 2. visit @ 文件列表
:: 对指定文件列表中的文件执行指定操作
::
:: 注意事项:
:: - 文件集/目录集 中可包含有效路径和通配符
:: - 路径缺省为当前路径,文件集缺省为 *.* (并非所有文件)
:: - 文件集/目录集 含空格时需用双引号引起
:: - [参数] 支持的dir开关: /s /a /o /l等不与 /b 冲突者
:: - [参数] 不支持的dir开关: /w /p /v 等与 /b 冲突者
:: - [操作] 由调用者预先写入 visitcmd.bat 中
:: - [操作] 中使用 %visitfile% 引用遍历文件
:: - 程序检查检查 [文件列表] 是否存在,但不检查它是否有效
:: - 不遍历隐藏/系统目录下的目录和文件(在命令行中指定时例外)
::
:: 用法示例:
:: visit c:\ /ad /s 遍历c盘所有目录,包含子目录
:: visit "c:\my document" /a-d 遍历"c:\my document"下所有文件
:: visit c:\*.zip /a /s 遍历c盘所有.zip压缩包,包含子目录
:: 如想遍历多个文件/目录集,可多次使用"dir 文件集 /a /s>>文件列表"
:: 生成一个完整的文件列表,再使用文件列表进行遍历;或者使用visitce.bat
:: 在遍历未显式指定的隐藏/系统目录时,可以用"attrib 文件集 /s"生成
:: 文件列表,然后在visitcmd.bat的代码中引用%visitfile%第三至最后的串,
:: 再使用文件列表进行遍历
::
:: 测试报告:
:: 在 win98 命令行方式下有限黑箱测试通过
:: 性能仍然是最大的瓶颈
::
@echo off
if "%1"=="@" goto copylist
:makelist
dir /b %1 %2 %3 %4 %5 %6 > ~
find "~" /v < ~ > ~
if not errorlevel 1 copy ~ ~>nul
goto makepreline
:copylist
if not [%2]==[] if exist %2 copy %2 ~>nul
if not exist ~ goto end
:makepreline
echo set visitfile=> ~
for %%c in (rcx e w q) do echo %%c>> ~
debug ~ < ~ > nul
if [%os%]==[windows_nt] chcp 936 > nul
:loopvisit
copy ~+~ ~ > nul
find "set visitfile=" < ~ > ~visit.bat
call ~visit.bat
if "%visitfile%"=="" goto clear
if not exist visitcmd.bat echo visiting %visitfile%
if exist visitcmd.bat call visitcmd.bat
find "set visitfile=" /v < ~ > ~
goto loopvisit
:clear
del ~visit.*
set visitfile=
:end
visitce.bat - 文件遍历批处理程序命令行增强版
:: visitce.bat - 文件遍历批处理程序命令行增强版
:: will sort - 10/17/2004 - v2ce
::
:: 程序用途:
:: 对指定路径/文件列表下的指定文件/目录集执行指定操作
::
:: 命令行说明:
:: 1. visit [路径1 路径2...] [开关1 开关2...] [文件集1 文件集2...]
:: 对 [路径] 和 [开关] 限定下的 [文件集] 执行指定操作
:: 2. visit @ 文件列表1 [文件列表2...]
:: 对指定 [文件列表] 中的文件执行指定操作
::
:: 注意事项:
:: - [路径] [参数] [文件集] 均可不选或多选
:: - [路径] 中不可包含通配符,[文件集] 中可包含有效路径和通配符
:: - [路径] 缺省为当前路径,[文件集] 缺省为 *.* (并非所有文件)
:: - [路径] [文件集] 含空格时需用双引号引起
:: - [参数] 支持的dir开关: /s /a /o /l等不与 /b 冲突者
:: - [参数] 不支持的dir开关: /w /p /v 等与 /b 冲突者
:: - [操作] 由调用者预先写入 visitcmd.bat 中
:: - [操作] 中使用 %visitfile% 引用遍历文件
:: - 程序检查检查 [文件列表] 是否存在,但不检查它是否有效
:: - 不遍历隐藏/系统目录下的目录和文件(在命令行中指定时例外)
::
:: 用法示例:
:: visit c:\ /ad /s 遍历c盘所有目录,包含所有子目录
:: visit "c:\my document" /a-d 遍历"c:\my document"下所有文件
:: visit c:\ d:\ e:\ /s /a /on 遍历c,d,e中所有文件,并按文件名排序
:: visit \ /a 遍历当前盘根目下所有文件和目录
:: 在遍历未显式指定的隐藏/系统目录时,可以用"attrib 文件集 /s"生成
:: 文件列表,然后在visitcmd.bat的代码中引用%visitfile%第三至最后的串,
:: 再使用文件列表进行遍历
::
:: 测试报告:
:: 在 win98 命令行方式下有限黑箱测试通过
:: 性能仍然是最大的瓶颈
::
@echo off
if "%1"=="$" goto makelist
if "%1"=="@" goto copylist
if "%1"=="" goto end
set visitcommand=%0
:getargu
:getpath
if not exist %1.\nul goto getswitch
set visitpath=%visitpath% %1
goto getnext
:getswitch
echo %1 | find "/" > nul
if errorlevel 1 goto getfilter
set visitswitch=%visitswitch% %1
goto getnext
:getfilter
echo %1 | find "*" > nul
if not errorlevel 1 goto setfilter
echo %1 | find "?" > nul
if errorlevel 1 goto end
:setfilter
set visitfilter=%visitfilter% %1
:getnext
shift
if not [%1]==[] goto getargu
%visitcommand% $ %visitfilter%
:makelist
if not [%visitpath%]==[] goto formake
:dirmake
dir %2 /b %visitswitch% >> ~
goto makenext
:formake
for %%p in (%visitpath%) do dir %%p.\%2 /b %visitswitch% >> ~
:makenext
shift
if not [%2]==[] goto makelist
find "~" /v < ~ > ~
if not errorlevel 1 copy ~ ~>nul
goto makepreline
:copylist
if not [%2]==[] if exist %2 type %2>>~
shift
if not [%2]==[] goto copylist
:makepreline
if not exist ~ goto end
echo set visitfile=> ~
for %%c in (rcx e w q) do echo %%c>> ~
debug ~ < ~ > nul
if [%os%]==[windows_nt] chcp 936 > nul
:loopvisit
copy ~+~ ~ > nul
find "set visitfile=" < ~ > ~visit.bat
call ~visit.bat
if "%visitfile%"=="" goto clear
if not exist visitcmd.bat echo visiting %visitpath% %visitswitch% %visitfilter% - %visitfile%
if exist visitcmd.bat call visitcmd.bat
find "set visitfile=" /v < ~ > ~
goto loopvisit
:clear
for %%f in (~visit.*) do del %%f
for %%e in (command path switch filter file) do set visit%%e=
:end
在2000sp4 下出现类似的问题,第二个问题实际上也是fc的不兼容问题,他在按行号显示时,每行文字前有8 个字节位,而不是dos6和win9x 下的9 个,所以解决起来也很简单,将debug 脚本中的 e 100 'set file='改为 e 100 'set fil=' 即可。
但是,这只是就事论事而已,以上的提到的三个批处理,只是我在dos 下练兵用的试验原型,做得很粗糙,自从今年3 月份正式转向win98 之后,使用中遇到了很多新问题,比如文件名包含空格的问题,系统/ 隐藏属性目录的问题;在nt下使用,又遇到了中文文件名的问题;而且由于循环体中使用了过多的文本流控制,导致了效率的严重低下;另外,三个程序功能上和实现上并没有太大的差别,没有拆分的必要。
综所上述,将以上代码重写就成为必须。合并代码,弥补漏洞,改善性能,书写文档,就出现了所谓的 v2 版,这中间其实并没有花很多功夫。
然而,一个偶然的下午,突然心血来潮,何不将visit 的命令行功能做一下增强,比如支持多个路径、多个过滤器(filter)、多个文件列表,原想只是加一个命令行参数分析循环,然而真正实现起来,却再次体会到了命令行的复杂,if for嵌套时冲定向输出,判定目录时根目录与子目录的不同,for 对过滤器的低能替换(win9x/dos) ,一个个新问题摩肩接踵,层出不穷,竟然整整耗了我大半个工作日的时间,才勉强实现了一个粗糙的版本,这就是所谓的 v2ce 版,对与严格的测试我没有多大的信心。
现在,再回头看我的工作,其实那个 v2ce 版其实是没有多大的应用价值。多个路径和过滤器,完全可以通过多次调用visit 来实现,而且实际上,我们大多数情况下只用一个路径和过滤器;而且,多参数控制带来了易用度的下降,用户总是对参数繁多的程序有一定的心理障碍,我个人对dos 压缩软件的爱好,从高到低依次是rar,zip,arj, 易用度就是第一靠量;另外,最重要的是,多参数控制导致了代码量和复杂性的大幅提升,这个程序一度让我钻进了if for构建的幽魂迷宫而不知南北西东,程序的可读性越来越差,调试起来也越来越困难,同时兼容性上拉上了更多的绊马索。
这些,就是功能提升所付出的代价,虽然这只是一个比较极端的例子,但是功能与简洁的平衡在程序设计的其重要性可见一斑。亲和性的界面并不意味着亲和性的代码,人性化的需求并不意味着人性化的实现,一味将使用方的复杂性转嫁给设计者(比如windows), 并不是一个很聪明的主意,反之亦然(比如linux ),这尚不考虑代码功能增强对设计方和使用方的双重施压。
d:\test
---a folder 1
|-----a file 1.txt
|-----a file 2.txt
|-----a file 3.txt
---b folder 2
|-----b file 1.txt
|-----b file 2.txt
|-----b file 3.txt
|---b folder 3
|-----b sub file 1.txt
|-----b sub file 2.txt
|-----b sub file 3.txt
复制代码 代码如下:
@echo off
set work_path=d:\test
d:
cd %work_path%
for /r %%s in (.,*) do (
echo %%s
)
pause
结果
d:\test\.
d:\test\a folder 1\.
d:\test\a folder 1\a file 1.txt
d:\test\a folder 1\a file 2.txt
d:\test\a folder 1\a file 3.txt
d:\test\b folder 2\.
d:\test\b folder 2\b file 1.txt
d:\test\b folder 2\b file 2.txt
d:\test\b folder 2\b file 3.txt
d:\test\b folder 2\b folder 3\.
d:\test\b folder 2\b folder 3\b sub file 1.txt
d:\test\b folder 2\b folder 3\b sub file 2.txt
d:\test\b folder 2\b folder 3\b sub file 3.txt
复制代码 代码如下:
@echo off
set work_path=d:\test
d:
cd %work_path%
for /r %%s in (.) do (
echo %%s
)
pause
结果
d:\test\.
d:\test\a folder 1\.
d:\test\a folder 1\a file 1.txt
d:\test\a folder 1\a file 2.txt
d:\test\a folder 1\a file 3.txt
d:\test\b folder 2\.
d:\test\b folder 2\b file 1.txt
d:\test\b folder 2\b file 2.txt
d:\test\b folder 2\b file 3.txt
d:\test\b folder 2\b folder 3\.
d:\test\b folder 2\b folder 3\b sub file 1.txt
d:\test\b folder 2\b folder 3\b sub file 2.txt
d:\test\b folder 2\b folder 3\b sub file 3.txt
那么
复制代码 代码如下:
for /r %%s in (.,*) do (
echo %%s
)
和
复制代码 代码如下:
for /r %%s in (.) do (
echo %%s
)
的区别是什么呢?
在有cd %work_path% 的时候,这两个命令执行的结果是一样的,就像我们上面举的例子。但是
for /r %%s in (.,*) do (
echo %%s
)
的批处理中没有cd %work_path% ,那么显示的将是这个批处理文件所在文件夹下面的遍历结果。
复制代码 代码如下:
@echo off
for /r "d:\test" %%s in (.) do (
echo %%s
)
pause
结果
d:\test\.
d:\test\a folder 1\.
d:\test\b folder 2\.
d:\test\b folder 2\b folder 3\.
复制代码 代码如下:
@echo off
for /r "d:\test" %%s in (.,*) do (
echo %%s
)
pause
结果
d:\test\.
d:\test\a folder 1\.
d:\test\a folder 1\a file 1.txt
d:\test\a folder 1\a file 2.txt
d:\test\a folder 1\a file 3.txt
d:\test\b folder 2\.
d:\test\b folder 2\b file 1.txt
d:\test\b folder 2\b file 2.txt
d:\test\b folder 2\b file 3.txt
d:\test\b folder 2\b folder 3\.
d:\test\b folder 2\b folder 3\b sub file 1.txt
d:\test\b folder 2\b folder 3\b sub file 2.txt
d:\test\b folder 2\b folder 3\b sub file 3.txt
这样的话看出来区别了吧。
再看一个=================================
复制代码 代码如下:
@echo off
for /r "d:\test" %%s in (*) do (
echo %%s
)
pause
结果
d:\test\a folder 1\a file 1.txt
d:\test\a folder 1\a file 2.txt
d:\test\a folder 1\a file 3.txt
d:\test\b folder 2\b file 1.txt
d:\test\b folder 2\b file 2.txt
d:\test\b folder 2\b file 3.txt
d:\test\b folder 2\b folder 3\b sub file 1.txt
d:\test\b folder 2\b folder 3\b sub file 2.txt
d:\test\b folder 2\b folder 3\b sub file 3.txt
就是只显示了文件
visitf.bat - 对指定路径指定文件进行遍历的程序
复制代码 代码如下:
:: visitf.bat - 对指定路径指定文件进行遍历的程序
:: 第一参数为要遍历的文件(支持通配符),第二参数为要遍历的路径(缺省为c盘根)
@echo off
:main
if [%1]==[] if not exist goto end
:init
if exist if exist goto loop
set file=%1
set base=%2
if [%2]==[] set base=c:
dir %base%\%file% /s /a /b >
echo e 100 ''set file='' >
echo w >>
echo q >>
:loop
fc nul /n | find " 1:" > setfile.bat
if errorlevel 1 goto restore
debug setfile.bat nul
call setfile.bat
echo visiting the file: %file%
:: user specified visit code replace this line
find "%file%" /v
copy > nul
goto loop
:restore
if exist del
if exist del
if exist del
if exist setfile.bat del setfile.bat
:end
visitd.bat - 对指定路径指定目录进行遍历的程序
复制代码 代码如下:
:: visitd.bat - 对指定路径指定目录进行遍历的程序
:: 第一参数为要遍历的目录(支持通配符),第二参数为要遍历的路径(缺省为c盘根)
@echo off
:main
if [%1]==[] if not exist goto end
:init
if exist if exist goto loop
set dir=%1
set base=%2
if [%2]==[] set base=c:
dir %base%\%dir% /s /ad /b >
echo e 100 'set dir=' >
echo w >>
echo q >>
:loop
fc nul /n | find " 1:" > setdir.bat
if errorlevel 1 goto restore
debug setdir.bat nul
call setdir.bat
echo visiting the dir: %dir%
:: user specified visit code replace this line
find "%dir%" /v
copy > nul
goto loop
:restore
if exist del
if exist del
if exist del
if exist setdir.bat del setdir.bat
:end
visitl.bat - 对指定文件列表中的文件进行遍历的程序
复制代码 代码如下:
:: visitl.bat - 对指定文件列表中的文件进行遍历的程序
:: 参数为要遍历的文件列表
@echo off
:main
if [%1]==[] if not exist goto end
:init
set filelist=%1
if [%1]==[] set filelist=
if not exist %filelist% goto end
copy %filelist% > nul
if exist goto loop
echo e 100 'set file=' >
echo w >>
echo q >>
:loop
fc nul /n | find " 1:" > setfile.bat
if errorlevel 1 goto restore
debug setfile.bat nul
call setfile.bat
echo visiting the file: %file%
:: user specified visit code replace this line
find "%file%" /v
copy > nul
goto loop
:restore
if exist del
if exist del
if exist del
if exist setfile.bat del setfile.bat
:end
visiti.bat - 对指定路径指定dir信息的文件进行遍历操作的的程序
复制代码 代码如下:
:: visiti.bat - 对指定路径指定dir信息的文件进行遍历操作的的程序
:: 第一参数为指定的dir信息项,第二参数为要遍历的路径(缺省为当前路径)
:: 注意:dir信息项可以是文件名,扩展名,日期,时间等dir命令提供的目录信息项
:: 可以同时使用多项,但必须加一对引号,参数格式也须严格符合dir的信息格式
@echo off
:main
if [%1]==[] goto end
:init
if exist if exist goto loop
set info=%1
set base=%2
if [%2]==[] set base=.
dir %base%\. /s /a /b >
echo e 100 ''''set file='''' >
echo w >>
echo q >>
:loop
fc nul /n | find " 1:" > setfile.bat
if errorlevel 1 goto restore
debug setfile.bat nul
call setfile.bat
dir "%file%" | find %info% > nul
if not errorlevel 1 echo visit file: "%file%"
:: if not errorlevel 1
find "%file%" /v
:: "%file%" 参数决定了所匹配的子目录下的所有文件和目录均不会再次匹配
copy > nul
goto loop
:restore
if exist del
if exist del
if exist del
if exist setfile.bat del setfile.bat
set info=
set file=
set base=
:end
visit.bat - 文件遍历批处理程序
复制代码 代码如下:
:: visit.bat - 文件遍历批处理程序
:: will sort - 10/17/2004 - v2
::
:: 程序用途:
:: 对指定文件集/目录集/文件列表执行指定操作
::
:: 命令行说明:
:: 1. visit 文件集/目录集 [参数]
:: 对文件集/目录集执行指定操作
:: 2. visit @ 文件列表
:: 对指定文件列表中的文件执行指定操作
::
:: 注意事项:
:: - 文件集/目录集 中可包含有效路径和通配符
:: - 路径缺省为当前路径,文件集缺省为 *.* (并非所有文件)
:: - 文件集/目录集 含空格时需用双引号引起
:: - [参数] 支持的dir开关: /s /a /o /l等不与 /b 冲突者
:: - [参数] 不支持的dir开关: /w /p /v 等与 /b 冲突者
:: - [操作] 由调用者预先写入 visitcmd.bat 中
:: - [操作] 中使用 %visitfile% 引用遍历文件
:: - 程序检查检查 [文件列表] 是否存在,但不检查它是否有效
:: - 不遍历隐藏/系统目录下的目录和文件(在命令行中指定时例外)
::
:: 用法示例:
:: visit c:\ /ad /s 遍历c盘所有目录,包含子目录
:: visit "c:\my document" /a-d 遍历"c:\my document"下所有文件
:: visit c:\*.zip /a /s 遍历c盘所有.zip压缩包,包含子目录
:: 如想遍历多个文件/目录集,可多次使用"dir 文件集 /a /s>>文件列表"
:: 生成一个完整的文件列表,再使用文件列表进行遍历;或者使用visitce.bat
:: 在遍历未显式指定的隐藏/系统目录时,可以用"attrib 文件集 /s"生成
:: 文件列表,然后在visitcmd.bat的代码中引用%visitfile%第三至最后的串,
:: 再使用文件列表进行遍历
::
:: 测试报告:
:: 在 win98 命令行方式下有限黑箱测试通过
:: 性能仍然是最大的瓶颈
::
@echo off
if "%1"=="@" goto copylist
:makelist
dir /b %1 %2 %3 %4 %5 %6 > ~
find "~" /v < ~ > ~
if not errorlevel 1 copy ~ ~>nul
goto makepreline
:copylist
if not [%2]==[] if exist %2 copy %2 ~>nul
if not exist ~ goto end
:makepreline
echo set visitfile=> ~
for %%c in (rcx e w q) do echo %%c>> ~
debug ~ < ~ > nul
if [%os%]==[windows_nt] chcp 936 > nul
:loopvisit
copy ~+~ ~ > nul
find "set visitfile=" < ~ > ~visit.bat
call ~visit.bat
if "%visitfile%"=="" goto clear
if not exist visitcmd.bat echo visiting %visitfile%
if exist visitcmd.bat call visitcmd.bat
find "set visitfile=" /v < ~ > ~
goto loopvisit
:clear
del ~visit.*
set visitfile=
:end
visitce.bat - 文件遍历批处理程序命令行增强版
复制代码 代码如下:
:: visitce.bat - 文件遍历批处理程序命令行增强版
:: will sort - 10/17/2004 - v2ce
::
:: 程序用途:
:: 对指定路径/文件列表下的指定文件/目录集执行指定操作
::
:: 命令行说明:
:: 1. visit [路径1 路径2...] [开关1 开关2...] [文件集1 文件集2...]
:: 对 [路径] 和 [开关] 限定下的 [文件集] 执行指定操作
:: 2. visit @ 文件列表1 [文件列表2...]
:: 对指定 [文件列表] 中的文件执行指定操作
::
:: 注意事项:
:: - [路径] [参数] [文件集] 均可不选或多选
:: - [路径] 中不可包含通配符,[文件集] 中可包含有效路径和通配符
:: - [路径] 缺省为当前路径,[文件集] 缺省为 *.* (并非所有文件)
:: - [路径] [文件集] 含空格时需用双引号引起
:: - [参数] 支持的dir开关: /s /a /o /l等不与 /b 冲突者
:: - [参数] 不支持的dir开关: /w /p /v 等与 /b 冲突者
:: - [操作] 由调用者预先写入 visitcmd.bat 中
:: - [操作] 中使用 %visitfile% 引用遍历文件
:: - 程序检查检查 [文件列表] 是否存在,但不检查它是否有效
:: - 不遍历隐藏/系统目录下的目录和文件(在命令行中指定时例外)
::
:: 用法示例:
:: visit c:\ /ad /s 遍历c盘所有目录,包含所有子目录
:: visit "c:\my document" /a-d 遍历"c:\my document"下所有文件
:: visit c:\ d:\ e:\ /s /a /on 遍历c,d,e中所有文件,并按文件名排序
:: visit \ /a 遍历当前盘根目下所有文件和目录
:: 在遍历未显式指定的隐藏/系统目录时,可以用"attrib 文件集 /s"生成
:: 文件列表,然后在visitcmd.bat的代码中引用%visitfile%第三至最后的串,
:: 再使用文件列表进行遍历
::
:: 测试报告:
:: 在 win98 命令行方式下有限黑箱测试通过
:: 性能仍然是最大的瓶颈
::
@echo off
if "%1"=="$" goto makelist
if "%1"=="@" goto copylist
if "%1"=="" goto end
set visitcommand=%0
:getargu
:getpath
if not exist %1.\nul goto getswitch
set visitpath=%visitpath% %1
goto getnext
:getswitch
echo %1 | find "/" > nul
if errorlevel 1 goto getfilter
set visitswitch=%visitswitch% %1
goto getnext
:getfilter
echo %1 | find "*" > nul
if not errorlevel 1 goto setfilter
echo %1 | find "?" > nul
if errorlevel 1 goto end
:setfilter
set visitfilter=%visitfilter% %1
:getnext
shift
if not [%1]==[] goto getargu
%visitcommand% $ %visitfilter%
:makelist
if not [%visitpath%]==[] goto formake
:dirmake
dir %2 /b %visitswitch% >> ~
goto makenext
:formake
for %%p in (%visitpath%) do dir %%p.\%2 /b %visitswitch% >> ~
:makenext
shift
if not [%2]==[] goto makelist
find "~" /v < ~ > ~
if not errorlevel 1 copy ~ ~>nul
goto makepreline
:copylist
if not [%2]==[] if exist %2 type %2>>~
shift
if not [%2]==[] goto copylist
:makepreline
if not exist ~ goto end
echo set visitfile=> ~
for %%c in (rcx e w q) do echo %%c>> ~
debug ~ < ~ > nul
if [%os%]==[windows_nt] chcp 936 > nul
:loopvisit
copy ~+~ ~ > nul
find "set visitfile=" < ~ > ~visit.bat
call ~visit.bat
if "%visitfile%"=="" goto clear
if not exist visitcmd.bat echo visiting %visitpath% %visitswitch% %visitfilter% - %visitfile%
if exist visitcmd.bat call visitcmd.bat
find "set visitfile=" /v < ~ > ~
goto loopvisit
:clear
for %%f in (~visit.*) do del %%f
for %%e in (command path switch filter file) do set visit%%e=
:end
在2000sp4 下出现类似的问题,第二个问题实际上也是fc的不兼容问题,他在按行号显示时,每行文字前有8 个字节位,而不是dos6和win9x 下的9 个,所以解决起来也很简单,将debug 脚本中的 e 100 'set file='改为 e 100 'set fil=' 即可。
但是,这只是就事论事而已,以上的提到的三个批处理,只是我在dos 下练兵用的试验原型,做得很粗糙,自从今年3 月份正式转向win98 之后,使用中遇到了很多新问题,比如文件名包含空格的问题,系统/ 隐藏属性目录的问题;在nt下使用,又遇到了中文文件名的问题;而且由于循环体中使用了过多的文本流控制,导致了效率的严重低下;另外,三个程序功能上和实现上并没有太大的差别,没有拆分的必要。
综所上述,将以上代码重写就成为必须。合并代码,弥补漏洞,改善性能,书写文档,就出现了所谓的 v2 版,这中间其实并没有花很多功夫。
然而,一个偶然的下午,突然心血来潮,何不将visit 的命令行功能做一下增强,比如支持多个路径、多个过滤器(filter)、多个文件列表,原想只是加一个命令行参数分析循环,然而真正实现起来,却再次体会到了命令行的复杂,if for嵌套时冲定向输出,判定目录时根目录与子目录的不同,for 对过滤器的低能替换(win9x/dos) ,一个个新问题摩肩接踵,层出不穷,竟然整整耗了我大半个工作日的时间,才勉强实现了一个粗糙的版本,这就是所谓的 v2ce 版,对与严格的测试我没有多大的信心。
现在,再回头看我的工作,其实那个 v2ce 版其实是没有多大的应用价值。多个路径和过滤器,完全可以通过多次调用visit 来实现,而且实际上,我们大多数情况下只用一个路径和过滤器;而且,多参数控制带来了易用度的下降,用户总是对参数繁多的程序有一定的心理障碍,我个人对dos 压缩软件的爱好,从高到低依次是rar,zip,arj, 易用度就是第一靠量;另外,最重要的是,多参数控制导致了代码量和复杂性的大幅提升,这个程序一度让我钻进了if for构建的幽魂迷宫而不知南北西东,程序的可读性越来越差,调试起来也越来越困难,同时兼容性上拉上了更多的绊马索。
这些,就是功能提升所付出的代价,虽然这只是一个比较极端的例子,但是功能与简洁的平衡在程序设计的其重要性可见一斑。亲和性的界面并不意味着亲和性的代码,人性化的需求并不意味着人性化的实现,一味将使用方的复杂性转嫁给设计者(比如windows), 并不是一个很聪明的主意,反之亦然(比如linux ),这尚不考虑代码功能增强对设计方和使用方的双重施压。
下一篇: cmd模式下中文乱码的解决方法(注册表)