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

[文本处理] 批处理怎么保留文件最高版本,然后把最高版本的版本号设置成1

文件夹下有软件生成的各个版本文件如下
      a.txt.1
      a.txt.2
      a.txt.3
....
      b.txt.4
      b.txt.10
      b.txt.15
...
      c.pro.22
      c.pro.50
      c.pro.51
....
      d.prt.4
      d.prt.100
      d.prt.201
....

类似的文件,怎么批处理后先保留最高版本,如上面文件执行后只保留的文件如下
      a.txt.3
....
      b.txt.15
...
      c.pro.51
....
      d.prt.201
....


然后把保留的最高版本号全部改成1,如下


      a.txt.1
....
      b.txt.1
...
      c.pro.1
....
      d.prt.1
....

想不明白了,改了多次啦,还是楼主来试试吧。bat文件保存为ANSI编码:
  1. @echo off
  2. setlocal enabledelayedexpansion
  3. for /f "delims=" %%i in ('dir /b /a-d ^|findstr /e "\.[1-9][0-9]*"') do (
  4.     set m=%%~xi
  5.     set m=!m:.=!
  6.     if not "%%~ni"=="!str1!" (
  7.         if defined str1 ren "!str1!!str2!" "!str1!.1"
  8.         set /a n=m
  9.         set str1=%%~ni
  10.         set str2=%%~xi
  11.     ) else (
  12.         if !m! gtr !n! (
  13.             set /a n=m
  14.             del "!str1!!str2!"
  15.             set str2=%%~xi
  16.         ) else (
  17.             del "%%i"
  18.         )
  19.     )
  20. )
  21. ren "!str1!!str2!" "!str1!.1"
  22. pause
复制代码
未经测试,请楼主自测。

TOP

本帖最后由 hfxiang 于 2022-11-3 08:53 编辑

测试一下用gawk( http://bcn.bathome.net/tool/4.1.0/gawk.exe )来处置,以下脚本在win10下工作正常:
  1. @echo off
  2. cd /d "%~dp0"
  3. dir/s/b/a-d|gawk "match($0,/(^.+\\)([^\\]+)\.([0-9]+)$/,arr){++i;b[i]=arr[2];c[i]=arr[3];d[i]=$0;if(f[arr[2]]+0<arr[3]){f[arr[2]]=arr[3]}}END{for(j=1;j<=i;j++)if(!(f[b[j]]==c[j])){print \"del \" \"\\\"\" d[j] \"\\\"\"}}"|cmd.exe
  4. dir/s/b/a-d|gawk "match($0,/(^.+\\)([^\\]+)\.([0-9]+)$/,arr){print \"move /Y \\\"\" $0 \"\\\" \\\"\" arr[1] arr[2] \".1\" \"\\\"\"}"|cmd.exe
复制代码

TOP

回复 2# qixiaobin0715


    谢谢,测试有效,

    再请教一下,如果子目录这样的文件一起呢,需要怎么修改

TOP

回复 4# 阿一呐法
想明白了也好改,看看3楼代码能否满足你的要求。

TOP

本帖最后由 WHY 于 2022-11-3 16:23 编辑
  1. @echo off
  2. PowerShell -c "dir -Literal '%~dp0' -Recurse | ?{ $_ -is [IO.FileInfo] -and $_.Extension -match '^\.[1-9]\d*$' } | sort{ 1 * $_.Extension.Trim('.') } | group{ $_.FullName -replace '\.\d+$' } | forEach{ $n = $_.Count - 1; for($i=0;$i -lt $n;$i++){ del -Literal $_.Group[$i].FullName -WhatIf } mv -Literal $_.Group[$n].FullName -Dest ($_.Name + '.1') -WhatIf }"
  3. pause
复制代码
WhatIf: 对目标“E:\Test\a.txt.1”执行操作“删除文件”。
WhatIf: 对目标“E:\Test\a.txt.2”执行操作“删除文件”。
WhatIf: 对目标“项: E:\Test\a.txt.3 目标: E:\Test\a.txt.1”执行操作“移动文件”。
WhatIf: 对目标“E:\Test\b.txt.4”执行操作“删除文件”。
WhatIf: 对目标“E:\Test\b.txt.10”执行操作“删除文件”。
WhatIf: 对目标“项: E:\Test\b.txt.15 目标: E:\Test\b.txt.1”执行操作“移动文件”。
WhatIf: 对目标“E:\Test\d.prt.4”执行操作“删除文件”。
WhatIf: 对目标“E:\Test\d.prt.100”执行操作“删除文件”。
WhatIf: 对目标“项: E:\Test\d.prt.201 目标: E:\Test\d.prt.1”执行操作“移动文件”。
WhatIf: 对目标“E:\Test\c.pro.22”执行操作“删除文件”。
WhatIf: 对目标“E:\Test\c.pro.50”执行操作“删除文件”。
WhatIf: 对目标“项: E:\Test\c.pro.51 目标: E:\Test\c.pro.1”执行操作“移动文件”。
请按任意键继续. . .

TOP

  1. @echo off & setlocal enabledelayedexpansion
  2. if "%~1" == "" (
  3.     for /f "tokens=1,3 delims=/" %%i in ('"%~f0" ARG ^| sort') do (
  4.         if /i "%%i" == "!f!" (
  5.             echo;del "!f!!e!"
  6.         ) else if defined f (
  7.             for /f "delims=" %%k in ("!f!") do echo;ren "!f!!e!" "%%~nxk.1"
  8.         )
  9.         set "f=%%i"
  10.         set "e=%%j"
  11.     )
  12.     if defined f (
  13.         for /f "delims=" %%k in ("!f!") do echo;ren "!f!!e!" "%%~nxk.1"
  14.     )
  15.     pause & exit
  16. ) else (
  17.     for /f "delims=" %%i in ('dir /b /a-d /s ^| findstr "\.[1-9][0-9]*$"') do (
  18.         for /f "delims=." %%j in ("%%~xi") do set "s=0000000000%%j"
  19.         echo;%%~dpni/!s:~-10!/%%~xi
  20.     )
  21. )
复制代码

TOP

本帖最后由 阿一呐法 于 2022-11-3 11:49 编辑

回复 6# WHY


    测试了,文件还在,并没有删除低版本,

TOP

回复 8# 阿一呐法
你不会把del、ren命令前面的echo;删除吗。

TOP

回复 9# qixiaobin0715


    没注意这具,谢谢了

TOP

楼上各位的代码效率???
看一楼的文件极似 CREO|PROE的工程文件的各种零件日志的版本文件。若是,这种脚本可以集成到 软件的快捷键中。若楼主刚入门工程做一些基础简单的产品,上面的代码都可以了。若已是大拿,一个产品就成百上千个子零件,各位的脚本得优化优化了。不建议使用 if /else find/str group 之类低效的命令。
  若楼主真是这行业。可以这样,找出后缀为数字的文件,排序。然后把文件一个个直接改名(硬改),不要做任何判断。 若是集成到软件中,不要用"%~dp0",要用"%~1"
俺曾经用的:效率刚刚的。下面的示范不能直接用于你的工作中,需要按你的要求修改。 还有那个后缀 ’.1' 去掉更好。去掉后就是标准的模板文件名。若不是该行业,那当这是废话。
  1. ls ".\*" -r|?{!$_.PsIsContainer -and $_.Extension -match '\.\d+$'}|sort @{e={$_.Extension.Trim('.') -as [int]}}|%{mv -Literal $_.FullName -dest ($_.DirectoryName+'\'+$_.BaseName+'.1') -Force;
  2. }
复制代码
// 快捷键写法
  1. mapkey $F12 @SYSTEMpurge & del /q *.out *.sec.* *.m_p *.acc.* *.err *.inf.* \
  2. mapkey(continued) *.crc.* *.log.* *.lst *.out *.pic *.pls *error.* *log.xml trail.txt* \
  3. mapkey(continued) *.ers* current_session.pro* *.bak.* \
  4. mapkey(continued) & call X:\\XX\\XX\\删后缀序号.bat;
复制代码
QQ: 己阵亡
脚本优先 [PowerShell win10]

TOP

回复 11# xczxczxcz


    "硬改"是个好办法,可以简化脚本。
我倒是觉得,既然用了管道,那么肯定不是特别在乎效率,管道与效率天生就是冤家。
有人很喜欢"管道一行流",还有人效率永远高于一切。
每个人习惯与认识不同,所用方法及思路就不同,仅此而已。

TOP

本帖最后由 WHY 于 2022-11-4 14:07 编辑

如果想要效率,那么sort可以不用、管道可以用 for 代替,代价是:脚本可能变长,变复杂。
  1. $path = $MyInvocation.MyCommand.Path -replace '\\[^\\]+$';  #当前脚本目录
  2. $hash = @{};
  3. $max  = @{};
  4. $files = dir -Literal $path -Recurse | ?{ $_ -is [IO.FileInfo] -and $_.Extension -match '^\.[1-9]\d*$' }
  5. $count = $files.Count;
  6. for( $i = 0; $i -lt $count; $i++ ){
  7.     $key = $files[$i].DirectoryName + '\' + $files[$i].BaseName;
  8.     $ext = 1 * $files[$i].Extension.Trim('.');
  9.     if( $hash[$key] -isNot [Collections.ArrayList] ){
  10.         $hash[$key] = [Collections.ArrayList]@();
  11.     }
  12.     [void]$hash[$key].Add( $files[$i].FullName );   #文件全名加入HashTable
  13.     if( $max[$key] -lt $ext ){ $max[$key] = $ext; } #最大版本号
  14. }
  15. forEach( $key In $hash.Keys ){
  16.     $maxFile = $key + '.' + $max[$key];             #最大版本号文件
  17.     if( $hash[$key].Count - 1 ){
  18.         $hash[$key].Remove( $maxFile );             #从数组移除
  19.         Remove-Item -Literal $hash[$key] -WhatIf;   #删除文件
  20.     }
  21.     Move-Item -Literal $maxFile -Dest ( $key + '.1' ) -WhatIf;  #移动(改名)
  22. }
  23. [Console]::ReadLine();
复制代码

TOP

回复 13# WHY

字典和哈希表还是有区别的(至少在偶的使用范畴中是区别开的)。
无论是先判断存内存中再删除 还是直接改名都要做相同次数的磁盘擦写处理。所以存内存判断再处理不可能更效率。

本层回复与该贴内容没有任何关系,属天马行空讨论。

字典的效率,偶深表怀疑。

用字典勿谈效率,要效率远离字典(若被CSDN之类‘科普文章’洗脑当偶没说)。少量数据字典有优势,大数据下整数的排序效率碾压字典。大数据下的字典类似BAT中的Findstr。大数据下要效率最好用哈希表或自定义带整型的数据类型,亲身经历大数据勿掉字典的坑中(现在的偶要求任何程序或脚本当动态数据量超过1000条时禁用字典,字典只用来存储一次性的数据,如表情包,还有html的节点属性查询和反射存储属性等简单场景)。
   另外如 -Unique 参数有去重功能,但这是一个不讲任何效率的参数。大量数据就会'死机',若去此参数改用哈希表包裹一下,几十万数据也哗啦一下就完成了。管道虽可以节流,但现在CPU强大,管道的性能损失也可以接受(大内存去管道更好)。可以照顾低内存用户(工程界里普通用户的机子内存一般都很小)。
   偶曾经的PC: 3570K+DDR3-16G+镁光初代固态;测字典多种数据量下的动态性能,1000/5000/10000/20000/50000/100000/200000/1000000,在1000内时效率还不错,5000以上没有性能,10000以上假死。但整数的SORT在100000量也是高效的。不同的硬件字典的效率临界区间可能不一样。

广告:
   .net 要效率每行都要琢磨(累,C++写则不用太多考虑性能但写得烦),偶的播放器(NET6写的,除一小部分用了指针)的性能与POT|SMPLAYER(C++) 毫不逊色(因内集成有开发帐号与各种网的解密不便发到网上)。


如有不同,还请见谅,’伟人‘说:实践是检验真理的唯一标准。任何理论不经过实践检验都是空洞的。
QQ: 己阵亡
脚本优先 [PowerShell win10]

TOP

回复 14# xczxczxcz


   
字典和哈希表还是有区别的(至少在偶的使用范畴中是区别开的)。


没用到Dictionary,只用到HashTable和ArrayList
键名=路径加文件名,键值=数组
无论是先判断存内存中再删除 还是直接改名都要做相同次数的磁盘擦写处理。所以存内存判断再处理不可能更效率。

效率的提升不是体现在擦写磁盘(文件删除),而是体现在遍历这些文件、处理这些文件的中间过程。
说直白点,就是以空间换时间。

TOP

返回列表