批处理从文本文件中删除重复的行
当然可以,但是像大多数批量处理文本文件一样,它并不漂亮,而且速度也不是特别快。
此解决方案在查找重复项时忽略大小写,并对行进行排序。该文件的名称作为批处理脚本的第一个参数和唯一参数传入。
@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%"
EDIT
上述条空行这两个解决方案。在谈论不同的价值时,我并不认为空白的线条值得保留。
我修改了两种解决方案来禁用FOR/F“EOL”选项,以便保留所有非空行,而不管第一个字符是什么。修改后的代码将EOL选项设置为换行字符。
新的解决方案2016年4月13日:JSORT.BAT
你可以用我JSORT.BAT hybrid JScript/batch utility高效排序和删除重复的线路用一个简单的衬垫(加上一个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文件名.ext
仅供参考:第一个'set'语句不会总是有效。我看到%CD%失败和/或被覆盖很多次!你应该使用这个,而不是'set“file =%〜dpnx1”'。 %1中的字母定义为:d =驱动器,p =路径,n =文件名(不带扩展名),x =扩展名。这适用于第一个参数,即使您只传入文件名(不含路径)。 – wasatchwizard 2013-09-24 19:17:22
是否遇到过这个问题,并且必须自己解决,因为这些使用对我的需求非常重要。 我需要找到重复的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需要在这篇文章中描述使用过滤设置变量:Escape double quotes in parameter
因此,而不是:
find "%%i" unique.txt 1>nul
它会更喜欢:
set test=%%i
set test=!test:"=""!
find "!test!" unique.txt 1>nul
因此,find会看起来像查找“”“什么”“”文件和%%我将保持不变。
我使用了一个假的“阵”来完成这项
@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的东西,是我已经成功嵌套for循环的唯一出路在彼此之内。基本上,这比较了每个作为分隔符传递的新值,如果没有匹配,那么程序会将该值添加到内存中。当它完成它会破坏目标文件的内容,并具有独特的琴弦
批处理文件下面你想要什么取代他们:
@echo off
setlocal EnableDelayedExpansion
set "prevLine="
for /F "delims=" %%a in (theFile.txt) do (
if "%%a" neq "!prevLine!" (
echo %%a
set "prevLine=%%a"
)
)
如果你需要一个更有效的方法,尝试这种分批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;
}
}
这两个方案是从this post复制。
纯批量 - 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
上它完美的作品。
Ran into finstr搜索字符串太长。 – 2016-03-28 07:47:36
@Dreadedsemicolon - 是的,我不认为如果由于FINDSTR限制,任何行超过长度511(XP上的127),第二个选项将失败。 – dbenham 2016-03-28 12:49:06