批处理从文本文件中删除重复的行

是否有可能从文本文件中删除重复的行? 如果是的话,怎么样?

当然可以,但是像大多数文本文件处理一样,它不是很漂亮,而且不是特别快。

这个解决方案在重复查找时会忽略大小写,并对行进行排序。 该文件的名称作为批处理脚本的第一个参数和唯一参数传入。

 @echo off setlocal disableDelayedExpansion set "file=%~1" set "sorted=%file%.sorted" set "deduped=%file%.deduped" ::Define a variable containing a linefeed character set LF=^ ::The 2 blank lines above are critical, do not remove sort "%file%" >"%sorted%" >"%deduped%" ( set "prev=" for /f usebackq^ eol^=^%LF%%LF%^ delims^= %%A in ("%sorted%") do ( set "ln=%%A" setlocal enableDelayedExpansion if /i "!ln!" neq "!prev!" ( endlocal (echo %%A) set "prev=%%A" ) else endlocal ) ) >nul move /y "%deduped%" "%file%" del "%sorted%" 

这个解决方案是区分大小写的,它保留了原来的顺序(当然除了重复)。 这个文件的名字再次作为第一个也是唯一的参数被传入。

 @echo off setlocal disableDelayedExpansion set "file=%~1" set "line=%file%.line" set "deduped=%file%.deduped" ::Define a variable containing a linefeed character set LF=^ ::The 2 blank lines above are critical, do not remove >"%deduped%" ( for /f usebackq^ eol^=^%LF%%LF%^ delims^= %%A in ("%file%") do ( set "ln=%%A" setlocal enableDelayedExpansion >"%line%" (echo !ln:\=\\!) >nul findstr /xlg:"%line%" "%deduped%" || (echo !ln!) endlocal ) ) >nul move /y "%deduped%" "%file%" 2>nul del "%line%" 

编辑

上面的两条解决方案空白行。 谈到不同的价值观时,我并不认为空白值得保留。

我已经修改了两个解决方案来禁用FOR / F“EOL”选项,以便保留所有非空行,而不管第一个字符是什么。 修改后的代码将EOL选项设置为换行字符。

新的解决方案2016-04-13:JSORT.BAT

您可以使用我的JSORT.BAT混合JScript /批处理实用程序来高效地排序和删除重复的行与简单的一个班轮(加MOVE覆盖原始文件与最终结果)。 JSORT是纯粹的脚本,可以在XP以后的任何Windows机器上本地运行。

 @jsort file.txt /u >file.txt.new @move /y file.txt.new file.txt >nul 
 set "file=%CD%\%1" sort "%file%">"%file%.sorted" del /q "%file%" FOR /F "tokens=*" %%A IN (%file%.sorted) DO ( SETLOCAL EnableDelayedExpansion if not [%%A]==[!LN!] ( set "ln=%%A" echo %%A>>"%file%" ) ) ENDLOCAL del /q "%file%.sorted" 

这应该完全一样。 dbenham的例子对我来说似乎太硬了,所以,测试了我自己的解决方案。 用法例如:filedup.cmd filename.ext

下面的批处理文件做你想要的:

 @echo off setlocal EnableDelayedExpansion set "prevLine=" for /F "delims=" %%a in (theFile.txt) do ( if "%%a" neq "!prevLine!" ( echo %%a set "prevLine=%%a" ) ) 

如果您需要更高效的方法,请尝试使用开发为过滤器的 Batch-JScript混合脚本,即类似于Unix uniq程序。 用.bat扩展名保存,就像uniq.bat一样:

 @if (@CodeSection == @Batch) @then @CScript //nologo //E:JScript "%~F0" & goto :EOF @end var line, prevLine = ""; while ( ! WScript.Stdin.AtEndOfStream ) { line = WScript.Stdin.ReadLine(); if ( line != prevLine ) { WScript.Stdout.WriteLine(line); prevLine = line; } } 

这两个程序都是从这个帖子复制的 。

纯批 – 3条有效线。

 @ECHO OFF SETLOCAL :: remove variables starting $ FOR /F "delims==" %%a In ('set $ 2^>Nul') DO SET "%%a=" FOR /f "delims=" %%a IN (q34223624.txt) DO SET $%%a=Y (FOR /F "delims=$=" %%a In ('set $ 2^>Nul') DO ECHO %%a)>u:\resultfile.txt GOTO :EOF 

如果数据不包含批次具有敏感性的字符,则可以愉快地工作。

“q34223624.txt”,因为问题34223624包含此数据

 1.1.1.1 1.1.1.1 1.1.1.1 1.2.1.2 1.2.1.2 1.2.1.2 1.3.1.3 1.3.1.3 1.3.1.3 

在它完美的作品。

我用一个假的“阵列”来完成这个

 @echo off :: filter out all duplicate ip addresses REM you file would take place of %1 set file=%1% if [%1]==[] goto :EOF setlocal EnableDelayedExpansion set size=0 set cond=false set max=0 for /F %%a IN ('type %file%') do ( if [!size!]==[0] ( set cond=true set /a size="size+1" set arr[!size!]=%%a ) ELSE ( call :inner if [!cond!]==[true] ( set /a size="size+1" set arr[!size!]=%%a&& ECHO > NUL ) ) ) break> %file% :: destroys old output for /L %%b in (1,1,!size!) do echo !arr[%%b]!>> %file% endlocal goto :eof :inner for /L %%b in (1,1,!size!) do ( if "%%a" neq "!arr[%%b]!" (set cond=true) ELSE (set cond=false&&goto :break) ) :break 

内部循环的标签的使用是特定于cmd.exe的东西,是唯一的方式,我已成功嵌套循环内彼此。 基本上这比较每个新的值作为分隔符传递,如果没有匹配,那么程序将把值添加到内存中。 完成之后,它将销毁目标文件内容,并用唯一的字符串替换它们

遇到这个问题,必须自己解决,因为使用微粒我的需要。 我需要找到重复的URL和行的顺序是相关的,所以它需要保存。 文本的行不应该包含任何双引号,不应该很长,排序不能使用。

所以我这样做了:

 setlocal enabledelayedexpansion type nul>unique.txt for /F "tokens=*" %%i in (list.txt) do ( find "%%i" unique.txt 1>nul if !errorlevel! NEQ 0 ( echo %%i>>unique.txt ) ) 

辅助:如果文本确实包含双引号,那么FIND需要使用一个过滤的设置变量,如本文所述: 在参数中使用双引号

所以,而不是:

 find "%%i" unique.txt 1>nul 

它会更像是:

 set test=%%i set test=!test:"=""! find "!test!" unique.txt 1>nul 

因此,找到将看起来像找“”“什么”“”文件和%%我将保持不变。