是否有可能从文本文件中删除重复的行? 如果是的话,怎么样?
当然可以,但是像大多数文本文件处理一样,它不是很漂亮,而且不是特别快。
这个解决方案在重复查找时会忽略大小写,并对行进行排序。 该文件的名称作为批处理脚本的第一个参数和唯一参数传入。
@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
因此,找到将看起来像找“”“什么”“”文件和%%我将保持不变。