kostyan
Goto Top

Mit Batchdatei aus einer .txt doppelte Zeilen löschen

Hallo Admins,

ich versuche mit Hilfe einer Batchdatei die Duplikate in einer .txt mit ca. 50.000 Einträgen zu löschen.
Dabei muss immer nur 1 Datensatz übrig bleiben und der doppelte Satz soll gelöscht werden.

Hinweis: Excel und Access ist keine Option, da die Struktur der .txt-Datei erhalten bleiben soll.

Also aus Duplikate.txt mit:

aaa
bbb
ccc
bbb
ccc

soll werden:

aaa
bbb
ccc


Ich habe bereits folgende Lösung hier gefunden :
Mit Batchdatei aus einer .txt alle doppelten Zeilen (Duplikate) komplett löschen

@echo off & setlocal
set "Datei=Daten.txt"
set "Bak=.bak"
set /a LineNo=0

move "%Datei%" "%Datei%%Bak%"
copy nul "%Datei%">nul
for /f "usebackq delims=" %%i in ("%Datei%%Bak%") do set "Zeile=%%i" & call :ProcessLine
del "%Datei%%Bak%"
goto :eof

:ProcessLine
set /a LineNo+=1
echo Validiere Zeile %LineNo% ...
goto :eof


Code funktioniert, aber leider wird bei jeder Zeile noch ein Leerzeichen am Ende eingefügt.
Hat jemand eine Idee wie man den Code ändern müsste? Oder vielleicht gibt es auch eine ganz andere Herangehensweise?
Vielen Dank im Voraus.

Content-Key: 213293

Url: https://administrator.de/contentid/213293

Ausgedruckt am: 28.03.2024 um 18:03 Uhr

Mitglied: bastla
bastla 03.08.2013 aktualisiert um 15:29:30 Uhr
Goto Top
Hallo kostyan und willkommen im Forum!

Das zusätzliche Leerzeichen am Zeilenende kann eigentlich nur aus einem unbeabsichtigten Leerzeichen in der vorletzten Zeile des Batches (am Ende nach %Zeile%) resultieren - bitte überprüfen ...

Grüße
bastla

P.S.: Mit "Code"-Formatierung (lässt sich auch nachträglich noch hinzufügen) wird ein Batch besser lesbar (und mit Zeilennummern) dargestellt ...
Mitglied: kostyan
kostyan 03.08.2013 um 16:00:40 Uhr
Goto Top
Hallo bastla,

danke für die schnelle Antwort. Deine Lösung klappt super.

Mir ist aber gerade noch aufgefallen, dass der Code nicht nur doppelte Zeilen löscht:

sondern aus...

aaa
aa
a

bleibt nur übrig...

aaa
Mitglied: Lochkartenstanzer
Lochkartenstanzer 03.08.2013 um 16:10:55 Uhr
Goto Top
Moin,

wäre es nicht einfacher einfach ein "sort -u textdatei.txt" drauf loszulasssen, z.B. mit einem Sort aus den GnuWin32 Coreutils oder Cygwin?

just my 0,02€.

lks
Mitglied: kostyan
kostyan 03.08.2013 um 16:22:50 Uhr
Goto Top
Das soll auf einem Firmen-PC funktionieren. Ich kann also keine Programme installieren.
Mitglied: Endoro
Endoro 03.08.2013 um 16:23:32 Uhr
Goto Top
Hallo,
ich hatte diesen code mal getestet, und er hat nicht funktioniert.
Es klappt nicht zuverlässig, aus einer Datei zu lesen, in die grad geschrieben wird.

Wenn keine = Zeichen vorkommen, würde ich die Zeilen in Variable packen.
Ansonsten mit sed oder sort oder sort+uniq aus GNUWin32 die Sache angehen.
lg.
Mitglied: Lochkartenstanzer
Lochkartenstanzer 03.08.2013 um 17:10:03 Uhr
Goto Top
Zitat von @Endoro:
Ansonsten mit sed oder sort oder sort+uniq aus GNUWin32 die Sache angehen.

"Sort -u" spart das uniq face-smile

lks
Mitglied: Lochkartenstanzer
Lochkartenstanzer 03.08.2013 um 17:12:48 Uhr
Goto Top
Zitat von @kostyan:
Das soll auf einem Firmen-PC funktionieren. Ich kann also keine Programme installieren.

Sort.exe ist nur ein binary und muß nicht installiert werden udn könnte sogar mit eingeschränkten benutzerrechten laufen.

lks

PS: Wie ich schon an naderer Stelle sagte: Man kann an einem Auto vieles mt dem Bordwerkzeug reparieren (sofern noch welches beiliegt), aber manchmal ist angepaßtes Werkzeug doch geeigneter.

lks
Mitglied: bastla
bastla 03.08.2013 aktualisiert um 17:46:42 Uhr
Goto Top
Hallo kostyan!
Mir ist aber gerade noch aufgefallen, dass der Code nicht nur doppelte Zeilen löscht:
Das liegt daran, dass nicht die komplette Zeile verglichen wird - so sollte das nicht mehr passieren:
echo off & setlocal
set "Datei=Daten.txt"  
set "Bak=.bak"  
set /a LineNo=0

move "%Datei%" "%Datei%%Bak%"  
copy nul "%Datei%">nul  
for /f "usebackq delims=" %%i in ("%Datei%%Bak%") do set "Zeile=%%i" & call :ProcessLine  
del "%Datei%%Bak%"  
goto :eof

:ProcessLine
set /a LineNo+=1
echo Validiere Zeile %LineNo% ...
findstr /xc:"%Zeile%" "%Datei%">nul || >>"%Datei%" echo %Zeile%  
goto :eof
Grüße
bastla
Mitglied: bastla
bastla 03.08.2013 aktualisiert um 18:16:23 Uhr
Goto Top
@ Endoro
Was meinst du mit
aus einer Datei zu lesen, in die grad geschrieben wird.
Es wird doch zuerst gelesen ("findstr") und erst danach geschrieben.

Wenn Du auf Nummer sicher gehen wolltest, könntest Du aber auch in eine Temp-Datei schreiben und diese beim nächsten Schleifendurchlauf (und nochmals nach der Schleife) wieder über die "Originaldatei" "moven" ...

Grüße
bastla
Mitglied: Endoro
Endoro 03.08.2013 um 18:31:27 Uhr
Goto Top
@bastla
ich habe diesen code in XP und Win8 getestet, er funktioniert nicht:
FOR /f "delims=" %%a IN (file1) DO FINDSTR /lxc:"%%a" file2 >NUL 2>&1|| >>file2 (ECHO(%%a)  
Es entsteht eine 1:1 Kopie, mit allen Duplikaten.
lg.
Mitglied: bastla
bastla 03.08.2013 aktualisiert um 18:50:38 Uhr
Goto Top
@ Endoro
Die Entsprechung zum Code oben wäre aber
FOR /f "delims=" %%a IN (file1) DO FINDSTR /lxc:"%%a" file2 >NUL 2>&1|| >>file2 ECHO %%a
Die leere "file2" hattest Du natürlich vorweg schon erzeugt ...

Grüße
bastla
Mitglied: Endoro
Endoro 03.08.2013 um 18:55:52 Uhr
Goto Top
@bastla,
die Klammern sind da nur zur Sicherheit.
Bei diesem code
@ECHO OFF &SETLOCAL
TYPE nul>file2
TYPE nul>file3
FOR /f "delims=" %%a IN (file1) DO (  
	MOVE file3 file2
	FINDSTR /lxc:"%%a" file2 >NUL 2>&1|| >>file2 ECHO(%%a  
	MOVE file2 file3
)
MOVE file3 file2
FC file1 file2
entsteht auch eine 1:1 Kopie :/
lg.
Mitglied: bastla
bastla 03.08.2013 aktualisiert um 19:04:46 Uhr
Goto Top
Hallo Endoro!

FINDSTR /lxc:"%%a" file2 >NUL 2>&1|| >>file2 ECHO(%%a 
sollte in diesem Fall "file3" vorkommen face-wink. Die Zeile 7 würde ich ganz einsparen.
Die Sicherheitsvariante (wegen allfälliger Sonderzeichen) sähe bei mir so aus:
copy nul file2>nul
FOR /f "delims=" %%a IN (file1) DO (  
    set "Zeile=%%a"  
    setlocal enabledelayedexpansion
    FINDSTR /lxc:"!Zeile!" file2 >NUL 2>&1||>>file2 ECHO !Zeile!  
    endlocal
)
Einzig Leerzeilen bleiben (in allen bisherigen Versionen) auf der Strecke ...

Grüße
bastla
Mitglied: Endoro
Endoro 03.08.2013 um 19:10:10 Uhr
Goto Top
Es hilft nix, es geht nicht :/
@ECHO OFF &SETLOCAL
TYPE nul>file2
TYPE nul>file3
FOR /f "delims=" %%a IN (file1) DO (  
	FINDSTR /lxc:"%%a" file2 >NUL 2>&1|| >>file3 ECHO(%%a  
	copy file3 file2 >nul
)
FC file1 file2
.. lässt sich nicht überlisten.
lg.
Mitglied: bastla
bastla 03.08.2013 um 20:19:22 Uhr
Goto Top
Hallo Endoro!

Kann ich nicht nachvollziehen - bei mir funktioniert auch diese Variante (getestet unter XP) ...

BTW: Die Klammer nach "ECHO" ist nicht nötig, da "%%a" nicht leer sein kann (darum werden ja auch Leerzeilen nicht in die Ergebnisdatei übernommen).
Mit meinem Ansatz oberhalb hast Du auch keinen Erfolg?

Grüße
bastla
Mitglied: Endoro
Endoro 03.08.2013 aktualisiert um 22:18:43 Uhr
Goto Top
@bastla,
ich habe jetzt mal die source gewechselt, und es geht.
Es lag an meinem Testfile, mit dem es nicht geht.
Ich hab's hier hochgeladen, das Forum zeigt es nicht ordentlich an.
Mit XML (oder ähnlichem) darf man also nicht unterwegs sein, was die Nützlichkeit einschränkt.

Zitat von @Lochkartenstanzer:
"Sort -u" spart das uniq face-smile

Am einfachsten wäre awk, da bleibt die Reihenfolge (anders als bei sort) erhalten face-smile
awk "!($0 in a); a[$0]" file1 > file2  
lg.

PS: Leerzeilen werden wie andere Zeilen behandelt, die erste wird ausgegeben, Duplikate face-smile nicht.
Mitglied: bastla
bastla 03.08.2013 aktualisiert um 21:59:43 Uhr
Goto Top
Hallo Endoro!

Batch mag in bestimmten Fällen Anführungszeichen als Textbestandteil noch weniger als andere Sonderzeichen (und "<" und ">" haben in "findstr" auch spezielle Funktionen) ...

Eine VBS-Alternative (die allerdings voraussetzt, dass die gesamte Ergebnisdatei in den Arbeitsspeicher passt) sähe etwa so aus:
Ein = "file1"  
Aus = "file2"  

Set fso = CreateObject("Scripting.FileSystemObject")  
Set DateiEin = fso.OpenTextFile(Ein)
Ergebnis = vbNewline
Do Until DateiEin.AtEndOfStream
    Zeile = DateiEin.ReadLine
    If Zeile <> "" Then 'Leerzeile  
        If InStr(Ergebnis, vbNewline & Zeile & vbNewline) = 0 Then Ergebnis = Ergebnis & Zeile & vbNewLine
    Else
        Ergebnis = Ergebnis & Zeile & vbNewLine
    End If
Loop
fso.CreateTextFile(Aus).Write Mid(Ergebnis, 3)
Hier würden (alle) Leerzeilen auch im Ergebnis aufscheinen.

Grüße
bastla
Mitglied: klausph
klausph 26.08.2015 um 12:06:50 Uhr
Goto Top
guten tag endoro (und alle anderen beteiligten face-wink

ich war gestern (im jahre 2015) auf der suche einem kommandozeilentool, was obige aufgabe erledigen soll (=sortieren, alle doppelten zeilen, bis auf die erste zeile, sollen gelöscht werden).
Lochkartenstanzer hat uniq.exe aus den gnutools_irgendwas empfohlen. hat bei mir nicht gekappt!
deine lösung mit awk bekomme ich ebenfalls nicht zum laufen, auch meine schlauen bücher zum thema awk helfen mir nicht weiter; bekommt man wirklich DEINE zeile SO unter win32 zum laufen? ich sach mal: nein face-wink

deshalb habe ich einige stunden gestern verbraucht, frauchen war sauer! und voila:
aber allen interessierten stelle ich jetzt mal "meine" lösung vor:

und sie ist so simpel! face-wink

1. erst mal sortieren, da gibt es ja einige programme...
und dann:

2. uniq.exe %tmp%\1 %tmp%\2
er löscht sehr schnell aus 1 die doppelten einträge raus!, und belässt in 2 den ersten drin!
die bedingung ist !aber!: zuerst sortieren!

uniq.exe ist ein programm aus dem paket: (Get)GnuWin32. und man benötigt mindesten diese dll dazu:
libintl3.dll (sorry, kann sein, daß es da noch eine zweite gibt...) DAS ist relativ großer nachteil von den gnu(nur von den?)-produkten: man darf nie die externen dll's vergessen.

nachsatz zum sortieren:
ich benutze das asort.exe aus der "bibliothekswelt", aus allegro-C. das ist nicht publicdomain. aber es gibt andere sorter, erstens dan von MS, sowie GNU und co. das dürfte NICZT das problem sein.....

viele grüße, klaus
Mitglied: reckheim
reckheim 26.08.2015 um 15:27:43 Uhr
Goto Top
Hallo
ich schreibe lange Übersetzungsprogramme in FoxPro in unten folgender Text-Datei-Form.
Die Datei ist allerdings durch Zusammenführung verschiedener Versionen voller Duplikate, welche gelöscht werden sollen.
Die Reihenfolge und alle Zeichen müssen unbedingt eingehalten werden.

Was für ein batch kommt da infrage ?


*
...
update papworth set deut = STRTRAN(deut,"cantoned", "bewink.")
update papworth set deut = STRTRAN(deut, 'waved & ', " gewellt u. ")
RETURN

Funktion frut
update papworth set deut = STRTRAN(deut,"cantoned", "bewink.")
RETURN

Funktion Klammer
*update papworth set deut = STRTRAN(deut,"]", "")
*update papworth set deut = STRTRAN(deut,"{ ", "{")
*update papworth set deut = STRTRAN(deut," }", "}")
*update papworth set deut = STRTRAN(deut,"( ", "(")
*update papworth set deut = STRTRAN(deut," )}", ")")
*update papworth set deut = STRTRAN(deut," ", " ")
*update papworth set deut = STRTRAN(deut," ", " ")
update papworth set deut = STRTRAN(deut," ;", ";")
update papworth SET deut = STRTRAN(deut,' &;',';')
RETURN
*
Mitglied: Endoro
Endoro 26.08.2015 um 17:50:25 Uhr
Goto Top
Zitat von @reckheim:

Hey, du müsstest einen neuen Thread erstellen, hier findet dich sonst niemand .


Zitat von @klausph:

deine lösung mit awk bekomme ich ebenfalls nicht zum laufen, auch meine schlauen bücher zum thema awk helfen mir nicht
weiter; bekommt man wirklich DEINE zeile SO unter win32 zum laufen? ich sach mal: nein face-wink
Ja, nur unter Windows, für Bash müssen die doppelten durch einfache Quotas ersetzt werden.

Gruss, Endoro
Mitglied: klausph
klausph 27.08.2015 um 09:50:57 Uhr
Goto Top
@reckheim
du "MUSST" das selber ausprobieren. das forum ist so voller ideen und lösungsansätze.

ich habe gestern ca 3-5 stunden gebraucht, um auf "meine" simple lösung zu kommen.

bin übrigens der meinung, daß die meinige auprobieren solltest.
je nach dem, welchen sorter du erwischt, kannst du den sorter auch auf die zu positionierende stelle setzen.(deine sternchen's könnten wichtig sein)
(ich glaube der windows-sorter kann das.) egal, das "MUSST" du selber rausfinden.

meine philosophie: 20 zeilen präsentieren, nach der geeigneten lösung fragen, ist nichts für die gehirnzellen.
selber denken, probieren, UND dann wenn man nicht weiterkommt, "klug" fragen face-wink
capisce?

grüße

ps: mir hat dieses forum schon sooo viel gebracht.
nebenbei: ich hoffe, auch anderen durch meine lösungen und ansätze geholfen zu haben. oooh, was habe ich schon für for-schleifen gemacht, dank des tutorials, was es hier zu for gibt. und wenn wirklich mal jemand mir eine lösung "fertig" präsentiert hat, solche "verrückten" gibt es hier, die setzen sich stunden hin, basteln die schönsten scripte, und voila! .. der satz geht weiter: ...präsentiert hat, dann wird er auch in meinem script mit copyright genannt. nebenbei2: sollte ich mit den lösungen geld verdienen, wird der urheber daran beteiligt! oder mindestens zum bierrundgang in die radeberger brauerei eingeladen!