11

是否可以从文本文件中删除重复的行?如果是,如何?

4

8 回答 8

13

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

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

@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/batch 实用程序通过一个简单的衬线有效地排序和删除重复行(加上一个 MOVE 以用最终结果覆盖原始文件)。JSORT 是纯脚本,可​​以在从 XP 开始的任何 Windows 机器上本地运行。

@jsort file.txt /u >file.txt.new
@move /y file.txt.new file.txt >nul
于 2012-07-27T16:33:31.627 回答
9

您可以使用来自UnxUtils http://sourceforge.net/projects/unxutils/的http://en.wikipedia.org/wiki/Uniquniq

于 2012-07-29T07:52:23.077 回答
3
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"

This should work exactly the same. That dbenham example seemed way too hardcore for me, so, tested my own solution. usage ex.: filedup.cmd filename.ext

于 2013-09-06T00:28:26.837 回答
3

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

@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 混合脚本,也就是类似于 Unixuniq程序。使用 .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;
   }
}

这两个程序都是从这篇文章中复制而来的。

于 2015-12-11T14:09:47.453 回答
2

前段时间我发现了一个出乎意料的简单解决方案,但不幸的是,这只适用于 Windows 10:该sort命令具有一些可以采用的未记录选项:

  • /UNIQ[UE]只输出唯一的行;
  • /C[ASE_SENSITIVE]区分大小写;

因此,使用以下代码行删除重复行(删除/C以不区分大小写的方式执行此操作):

sort /C /UNIQUE "incoming.txt" /O "outgoing.txt"

这会从 in 中的文本中删除重复的行,incoming.txt并在 中提供结果outgoing.txt。原来的顺序当然不会被保留(因为,嗯,这是 的主要目的sort)。

但是,您应该谨慎使用这些选项,因为它们可能存在一些(未知)问题,因为可能有充分的理由不记录它们(到目前为止)。

于 2020-04-14T22:59:21.447 回答
2

纯批次 - 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

它完美地工作。

于 2015-12-11T14:27:11.227 回答
1

确实遇到了这个问题并且不得不自己解决它,因为它的使用是我需要的。我需要找到重复的 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 看起来像 find """what""" 文件并且 %%i 将保持不变。

于 2014-12-09T05:55:08.950 回答
1

我使用了一个假的“数组”来完成这个

@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 循环嵌套在彼此中的唯一方法。基本上,这会比较作为分隔符传递的每个新值,如果没有匹配,则程序会将值添加到内存中。完成后,它将破坏目标文件的内容并用唯一的字符串替换它们

于 2015-01-10T07:08:07.630 回答