[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
返回列表 发帖

[文件操作] 求助批处理批量解决移动指定类型文件到上一级目录中

本帖最后由 mmm8422616 于 2024-4-10 11:00 编辑

多层级目录 最后一级目录下面有 .symlink .jgp .nfo 等等类型的文件 比如  D:\...\...\...\...\...\AAA\

求助批处理批量解决移动指定类型(比如.symlink)文件到上一级目录中,然后删除AAA下面的其他所有类型的其他文件(直接删除AAA文件夹及下面的文件)

哪位大大帮忙给实现一下啊 谢谢哦!

回复 37# aloha20200628
差距这么大,也许环境和目录结构的不同,测试结构也会不同,下面代码创建的空目录试了一下,相比较还好CALL并不是太耗资源,
  1. for /l %%a in (1,1,10) do  for /l %%b in (1,1,10) do for /l %%c in (1,1,10) do for /l %%d in (1,1,10) do for /l %%e in (1,1,10) do md test\%%a\%%b\%%c\%%d\%%e\ 2>nul   
复制代码

TOP

本帖最后由 aloha20200628 于 2024-4-14 19:04 编辑


用本帖到目前为止的3种典型的call方法(代码如下)再跑了几遍测试样本,与30楼所列方法1-3测试数据合并,能有一个更全面的结论...致谢30楼和36楼
  1. ::方法4
  2. set "n="&for /d /r %%d in (*) do (
  3. set "k=" &(call :x4 "%%~d" k)
  4. if not defined k set/a "n+=1"
  5. )
  6. echo,发现 %n% 个末级目录&pause&exit/b
  7. :x4
  8. for /d /r "%~1" %%d in (*) do (set "%~2=1"&exit/b)
  9. exit/b
复制代码
  1. ::方法5
  2. set "n="&for /d /r %%d in (*) do (
  3. set "k=" &(call :x5 "%%~d" k)
  4. if not defined k set/a "n+=1"
  5. )
  6. echo,发现 %n% 个末级目录&pause&exit/b
  7. :x5
  8. for /d %%d in ("%~1\*") do (set "%~2=1"&exit/b)
  9. exit/b
复制代码
  1. ::方法6
  2. set "n="&(call :x6 "%cd%")
  3. echo,发现 %n% 个末级目录&pause&exit/b
  4. :x6
  5. for /d %%d in ("%~1\*") do (set "d=%%d"&call :x6 "%%d")
  6. if defined d (set /a n+=1)
  7. set "d="&exit/b
复制代码
方法1-6测试数据合并如下
测试主目录及其文件和子目录体量                        方法1耗时/方法2耗时/方法3耗时/方法4耗时/方法5耗时/方法6耗时(耗时单位=秒)
c:\a1 148,814 个文件,32,751 个文件夹        255/275/783/1239/1149/741
c:\a2  30,262 个文件, 3,281 个文件夹        21/24/26/14/14/4
c:\a3  28,159 个文件, 2,114 个文件夹        13/15/15/6/6/2
c:\a4  16,916 个文件, 1,213 个文件夹        8/9/8/2/2/1
可见方法6采用了递归调用,没有方法4-5代码中宿主循环开销,效率倍增,但依然会在a1-a2样本之间遭遇 ‘拐点爆胎’,被方法1-2赶超...
另一点是如36楼所说会遗漏那些受保护(如隐藏)目录...
》以上仅供参考,有兴趣者还可参考以下老帖,融合体会一下call先生的功与过...
   一。批处理之家 » BAT教程&资料 » 讨论:批处理运行效率浅谈
   二。http://bbs.bathome.net/thread-4482-1-1.html
2

评分人数

TOP

本帖最后由 77七 于 2024-4-14 01:57 编辑

我找出原因了
用户\admin\appdata
这个目录使用for /r /d 能够遍历出来,使用for /d 则不能
惭愧惭愧,学习不思考......appdata下的子目录不具有隐藏属性,所以for /r /d遍历了appdata下的子目录,仍没有遍历出appdata
bat小白,请多指教!谢谢!

TOP

本帖最后由 77七 于 2024-4-14 01:00 编辑

回复 34# terse


  之前测试效率,被if () 搞中断了...
现在我测试了一下,大佬您的代码效率很高,测试样本仍然是32楼的那些,耗时20秒左右

样本说明:复制了整个c盘小于10kb的文件及目录,并手动复制了几次

可能是因为样本比较特殊,使用中出现了一些小插曲,大佬的代码遗漏了 ”用户\admin\appdata“ 目录下的末级目录
,到
  1. "f:\测试\Users - 副本 - 副本 (2)\admin\3D Objects"
复制代码
就结束了。

而dir 和call +for /d 均列出了
  1. "F:\测试\Users - 副本 - 副本\admin\AppData\Local\Microsoft\PowerShell\7.2.7"
复制代码
bat小白,请多指教!谢谢!

TOP

这样CALL,系统开销是否会有所不同呢
  1. @echo off
  2. call :listdir "%cd%"
  3. echo %n%
  4. pause
  5. exit
  6. :listdir
  7. for /d %%d in ("%~1\*") do (
  8.     set "d=%%d"
  9.     call :listdir "%%d"
  10. )
  11. if defined d (
  12.    set /an+=1
  13. )
  14. set "d="
复制代码

TOP

本帖最后由 aloha20200628 于 2024-4-13 22:11 编辑

回复 31# 77七

只要用call方法
   for /d %%d in ("%~1\*") do (set "%~2=1"&exit/b)

   for /d /r "%~1" %%d in (*) do (set "%~2=1"&exit/b)
两个句式的耗时差约在 0.07~0.05%,二者基本相当吧。
结论还是》一方面,得益于用call方法能使纯P代码从for循环中及时退出;另一方面,跑大体量数据到其“拐点”后就“怂”了...

TOP

本帖最后由 77七 于 2024-4-13 19:31 编辑

回复 30# aloha20200628


   大佬,我把c盘复制了5次66000文件,16000目录,末级目录10000个
测试了方法1、4,结论和大佬的一致
call +for /d 7分钟,dir 4分钟。call cpu占用比dir低。感觉dir在全力跑,call+for /d有点散步的意思
bat小白,请多指教!谢谢!

TOP

本帖最后由 77七 于 2024-4-13 18:55 编辑

回复 30# aloha20200628


   大佬,for /r "%~1"是我随手写的,如果目录非常庞大,dir /b /ad 没有/s ,没有遍历子目录,显然有失公平,使用/r应该徒增了很多无用功吧,以前我做过测试,for /r 的遍历机制,当处理到第一个(还是第二个,记不清了)目录的时候,大概已经完成了700多个目录的列举,(数据记得不是很清楚了)不知道这是否拉低了效率
麻烦大佬您再测试一下,for /d

  1. set "n="&for /d /r %%d in (*) do (
  2.         set "k=" &(call :xxx "%%~d" k)
  3.         if not defined k set/a "n+=1"
  4. )
  5. echo,发现 %n% 个末级目录&exit/b
  6. :xxx
  7.         for /d %%e in ("%~1\*") do (set "%~2=1"&exit/b)
  8.         exit/b
复制代码
bat小白,请多指教!谢谢!

TOP

本帖最后由 aloha20200628 于 2024-4-13 18:28 编辑


用本帖敲打一下 call 的功过,还是要看比较实际的测试结果,先看用于测试比对的四种方法,其各自代码如下
::方法1
  1. set "n="&for /d /r %%d in (*) do (
  2. dir /b/ad "%%~d\*" 2>nul | find /v "">nul || set/a "n+=1"
  3. )
  4. echo,发现 %n% 个末级目录&exit/b
复制代码
::方法2
  1. set "n="&for /d /r %%d in (*) do (
  2. dir /b/ad "%%~d\*" 2>nul | findstr ".">nul || set/a "n+=1"
  3. )
  4. echo,发现 %n% 个末级目录&exit/b
复制代码
::方法3
  1. set "n="&for /d /r %%d in (*) do (
  2. set "k=" &for /f "delims=" %%a in ('dir /b/ad "%%~d\*" 2^>nul') do set "k=1"
  3. if not defined k set/a "n+=1"
  4. )
  5. echo,发现 %n% 个末级目录&exit/b
复制代码
::方法4
  1. set "n="&for /d /r %%d in (*) do (
  2. set "k=" &(call :xxx "%%~d" k)
  3. if not defined k set/a "n+=1"
  4. )
  5. echo,发现 %n% 个末级目录&exit/b
  6. :xxx
  7. for /r "%~1" /d %%e in (*) do (set "%~2=1"&exit/b)
  8. exit/b
复制代码
看如下测试结果
测试主目录及其文件和子目录体量                方法1耗时/方法2耗时/方法3耗时/方法4耗时(耗时单位=秒)
c:\a1 148,814 个文件,32,751 个文件夹  255/275/783/1149
c:\a2   30,262 个文件,  3,281 个文件夹  21/24/26/14
c:\a3   28,159 个文件,  2,114 个文件夹  13/15/15/6
c:\a4   16,916 个文件,  1,213 个文件夹  8/9/8/2
c:\a5     1,248 个文件,     717 个文件夹  4/5/4/1
从以上结果数据可见,小体量样本测试证明方法4有明显优势,但大样本比对就出现了逆转。
至少两点结论》
其一是用方法3即纯P跟读目录列表的效率会随样本体量增大锐减(此点其实是老生常谈不足为奇);
其二是“call乃效率大杀器”的杀气要在足够大体量的数据样本中才会凸显,在a1和a2体量之间存在一个令call从“英雄变狗熊”的拐点...
1

评分人数

    • 77七: 感谢分享技术 + 1

TOP

本帖最后由 77七 于 2024-4-12 16:52 编辑

回复 28# terse


   谢谢大佬指点!特殊字符与变量延迟扩展的关系真是奇妙!开启变量延迟扩展不当则会漏掉特殊字符“!”本身,但更多情况是成就了更多特殊字符。
bat小白,请多指教!谢谢!

TOP

回复 27# 77七
是的,这里是开了延迟的,可以!str!

TOP

回复 26# terse


   谢谢大佬指点!引号确实能解决此例中的显示问题,但我想到遇到其它问题的时候可能不需要引号
我又试着开启变量延迟扩展,结果正确
  1. @echo off
  2. set str=D:\\1\新建文件夹 (2)
  3. if defined str (
  4. setlocal enabledelayedexpansion
  5. echo !str!
  6. endlocal
  7. )
  8. pause
复制代码
bat小白,请多指教!谢谢!

TOP

本帖最后由 terse 于 2024-4-12 16:34 编辑

回复 25# 77七
加引号
其实这里是开了延迟的,可以!str!这样!str!

TOP

本帖最后由 77七 于 2024-4-12 16:20 编辑

回复 24# 77七


   我找到原因了,去掉()则正确
  1. if defined d echo %d%
复制代码


这个if 和 () 真是纠缠不清啊,这都能出错...这个直接颠覆了我的认知,以前一直以为明着写才会出错
再次验证
  1. @echo off
  2. set str=D:\\1\新建文件夹 (2)
  3. if defined str (
  4.         echo %str%
  5. )
  6. pause
复制代码


结果还是错的

幸好以前跟aloha20200628大佬学了一招,使用set /p=""<nul,保留特殊字符,双引号直接把()打出原形
  1. @echo off
  2. set str=D:\\1\新建文件夹 (2)
  3. if defined str (
  4.         set /p="%str%"<nul
  5.         echo=
  6. )
  7. pause
复制代码


结果正确
想到aloha20200628大佬提到 set /p=""<nul无法保留前置空格,看来也不是个完美办法
  1. @echo off
  2. set str= D:\\1\新建文件夹 (2)
  3. if defined str (
  4. for /f "delims=" %%x in ("%str%") do (
  5. echo %%x
  6. )
  7. )
  8. pause
复制代码


难道只能这样了?...
bat小白,请多指教!谢谢!

TOP

返回列表