Jump to content

CSV doppelte Zeilen löschen


Der letzte Beitrag zu diesem Thema ist mehr als 180 Tage alt. Bitte erstelle einen neuen Beitrag zu Deiner Anfrage!

Empfohlene Beiträge

Hallo werte Forengemeinde,

 

ich beisse mich seit einigen Tagen an einem Problem fest, was wohl laut diverser Foren viele haben, dafür gab es auch schon haufenweise Lösungsvorschläge, aber nichts davon führte bei mir zum Erfolg. Es geht darum dass ich eine Inventarliste im CSV Format (kommagetrennt) habe, die sieht folgendermassen aus (Spaltenanzahl und Zeilenanzahl aus Komplexitätsgründen gekürzt)

 

Zitat

Hostname    Timestamp             Serial Number       Manufacturer          Model       
RTA190504    11.11.2021 14:25    S4JY3833         LENOVO            30C5003CGE       
RTA200601    11.11.2021 12:23    CZC02286W9        HP                HP ProDesk 600
RTA201201    27.09.2021 08:39    33M6933            Dell Inc.         OptiPlex 3070    
RTX54011      15.07.2021 18:19    7739-6127        Microsoft        Virtual Machine    
NTX210708    12.11.2021 21:02    PF2WCBGR        LENOVO            82GN    
NTX210708    13.11.2021 11:31    PF2WCBGR        LENOVO            82GN    
NTX210708    13.11.2021 11:32    PF2WCBGR        LENOVO           82GN    
NTX210708    13.11.2021 11:30    PF2WCBGR        LENOVO            82GN    
NTX210708    13.11.2021 11:31    PF2WCBGR        LENOVO            82GN    
NTX210708    13.11.2021 11:33    PF2WCBGR        LENOVO            82GN   

Wie hier deutlich zu sehen sind von NTX210708 mehere Einträge vorhanden. Ist es möglich per Batch oder auch per PS alle doppelten Zeilen zu löschen, Dabei sollen die Zeilen behalten werden die dem aktuellstzen Timestamp entsprechen. In dem Fall von NTX... also der letzte.

 

Vielleicht hat ja einer eine Idee?

 

 

lg und schönes we

 

 

Stef

Link zu diesem Kommentar

Hi,

 

was hast du denn so an Lösungsvorschlägen bereits umgesetzt? Generell ist das mit "Import-CSV (Import-Csv (Microsoft.PowerShell.Utility) - PowerShell | Microsoft Docs)" und ein bisschen Logik flott erledigt. In quick'n'dirty:

$CSVPath = "<Pfad zur CSV>"
$objCSVInput = Import-Csv -Path $CSVPath `
    -Delimiter ","
$objHostnames = $objCSVInput |
    Select-Object Hostname -Unique

$objCSVSorted = @()
foreach($Hostname in $objHostnames.Hostname){
    $objCSVSorted += $objCSVInput |
        Where-Object { $_.Hostname -eq $Hostname } |
            Sort-Object Timestamp |
                Select-Object -Last 1
}

$objCSVSorted

 

Gruß

Jan

bearbeitet von testperson
Link zu diesem Kommentar

@testperson Das würde funktionieren, wenn Import-CSV das Timestamp-Feld als [datetime] importieren würde. Da es aber ein String bleibt, ist '01.01.2021 12:30' < '12.12.1999 13:45'

Mein Vorschlag wäre

$data = Import-CSV C:\temp\machines.csv
$lastTS = @{}
$output = @{}
for ($i=0; $i -lt $data.Count; $i++) {
    $curHostname = $data[$i].Hostname
    $curTS = $data[$i].Timestamp -as [datetime]
    if ($lastTS.ContainsKey($curHostname)) {
        if ($lastTS[$curHostname] -lt $curTS) {
            $lastTS[$curHostname] = $curTS
            $output[$curHostname] = $i
        }
    } else {
        $lastTS.Add($curHostname, $curTS)
        $output.Add($curHostname, $i)
    }
}
$outputSorted = New-Object System.Collections.Generic.List[PSObject]
foreach($i in $output.Values) {
    $outputSorted.Add($data[$i])
}
$outputSorted | Export-CSV -Path c:\temp\machines-sorted.csv -Delimiter ',' -NoTypeInformation

Vermutlich ließe er sich bei sehr großen Datenmengen nochmal optimieren, aber er dürfte schneller sein als alles, was mit der Pipe und Sort-Object arbeitet.

bearbeitet von cj_berlin
Link zu diesem Kommentar

@cj_berlin Das sollte sich doch in meinem Code so lösen lasse:

$CSVPath = "C:\install\test\test.csv"
$objCSVInput = Import-Csv -Path $CSVPath `
    -Delimiter ","
$objHostnames = $objCSVInput |
    Select-Object Hostname -Unique

$objCSVSorted = @()
foreach($Hostname in $objHostnames.Hostname){
    $objCSVSorted += $objCSVInput |
        Where-Object { $_.Hostname -eq $Hostname } |
            Sort-Object [datetime]::Timestamp |
                Select-Object -Last 1
}

$objCSVSorted

 

Link zu diesem Kommentar

Funktional schon :-) Und es erschließt sich aus Deinem Code für den Laien vermutlich auch besser, was der Code wo tut.

 

Aber: ich habe hier eine Datei mit 100k Zeilen für insgesamt 1000 Hostnames, also quasi real-world data aus einem mittelständischen Unternehmen. Mein obiger Code war damit in unter zwei Sekunden fertig. Dahingegen hat auf demselben Rechner allein der Part mit Select -Unique 30-40 Sekunden in Anspruch genommen.

 

Hier mit Hard Facts:

image.png.b96a15497f072bf6e329657e60550190.png

bearbeitet von cj_berlin
Link zu diesem Kommentar

Also ich hatte es folgendermaaßen probiert, nachdem ich mit Batch absolut nicht weiterkam:

 

Zitat

#Getting the Path of CSV file
$inputCSVPath = 'Summary.csv'
#The Import-Csv cmdlet creates table-like custom objects from the items in CSV files
$inputCsv = Import-Csv $inputCSVPath | Sort-Object Timestamp -Unique
#The Export-CSV cmdlet creates a CSV file of the objects that you submit.
#Each object is a row that includes a comma-separated list of the object's property values.
$inputCsv | Export-Csv "C:\Users\Riegert\Desktop\CSVmerge\Final.csv"  -NoTypeInformation

Die Reihenfolge ist im Prinzip ertmal egal, klar wärs schön wenns nach Host sortiert wäre. Danke aber nochmal für die interessanten Lösungsansätze, werde ich mich mal durcharbeiten, melde mich dann wieder

 

 

lg

 

Stef

 

 

Also folgendes:

 

Also prinipiell scheint er bei allen Lösungen etwas zu machen, also auch keine doppelten, aber es schreibt leider keine Ergennis CSV. Schon komisch dass ich in anderen Foren zu dem Thema nur "Müll" gefunden habe.

 

@CJ Wie bekomme ich es bei Deinem Ansatz hin dass er eine neue Datei schreibt, so im Fenster kann ich damit nicht viel anfangen, bin leioder noch nicht ganz so firm in Powershell, obgleich ich zugeben muss, dass man damit schon mehr anfangen kann als mit Batch.

 

lg

 

Stef

 

 

 

Link zu diesem Kommentar

Moin,

 

in beiden Varianten machst Du am Ende | Export-CSV -Path <Pfad> -Delimiter ',' -NoTypeInformation :-)

Aber ich ergänze mal den obigen Code um eine Sammlung.

 

EDIT: Code inklusive CSV-Ausgabe ist drin. Wenn Du möchtest, dass die CSV in Excel mit Doppelklick aufgeht, musst Du den Delimiter auf ';' setzen.

bearbeitet von cj_berlin
Link zu diesem Kommentar

Ich bin mir nicht sicher, ob ich dich richtig verstanden habe, du meintest sicher jeweils in den Zeilen mit Output:

 

Zitat

$data = Import-CSV C:\SC\CSVmerge\Summary.csv
$lastTS = @{}
$output = @{}
for ($i=0; $i -lt $data.Count; $i++) {
    $curHostname = $data[$i].Hostname
    $curTS = $data[$i].Timestamp -as [datetime]
    if ($lastTS.ContainsKey($curHostname)) {
        if ($lastTS[$curHostname] -lt $curTS) {
            $lastTS[$curHostname] = $curTS
            $output[$curHostname] = $i | Export-CSV -Path C:\SC\CSVmerge\output.csv -Delimiter ',' -NoTypeInformation
        }
    } else {
        $lastTS.Add($curHostname, $curTS)
        $output.Add($curHostname, $i) | Export-CSV -Path C:\SC\CSVmerge\output.csv -Delimiter ',' -NoTypeInformation
    }
}
foreach($i in $output.Values) {
    $data[$i]
}

die Outputdatei ist 1kb groß und zeigt beim öffnen keinen Inhalt, vielleicht fehlen mir ja noch irgendwelche cmdlets, die ich erst isstallieren muss

Link zu diesem Kommentar

Also jetzt hab ichs so, der Pfad zu Summary.csv stimmt, aber jetzt macht er gar nichts

 

data = Import-CSV C:\SC\CSVmerge\Summary.csv
$lastTS = @{}
$output = @{}
for ($i=0; $i -lt $data.Count; $i++) {
    $curHostname = $data[$i].Hostname
    $curTS = $data[$i].Timestamp -as [datetime]
    if ($lastTS.ContainsKey($curHostname)) {
        if ($lastTS[$curHostname] -lt $curTS) {
            $lastTS[$curHostname] = $curTS
            $output[$curHostname] = $i
        }
    } else {
        $lastTS.Add($curHostname, $curTS)
        $output.Add($curHostname, $i)
    }
}
$outputSorted = New-Object System.Collections.Generic.List[PSObject]
foreach($i in $output.Values) {
    $outputSorted.Add($data[$i])
}
$outputSorted | Export-CSV -Path C:\SC\CSVmerge\machines-sorted.csv -Delimiter ',' -NoTypeInformation

:(

 

lg

 

stef

Link zu diesem Kommentar
Der letzte Beitrag zu diesem Thema ist mehr als 180 Tage alt. Bitte erstelle einen neuen Beitrag zu Deiner Anfrage!

Schreibe einen Kommentar

Du kannst jetzt antworten und Dich später registrieren. Falls Du bereits ein Mitglied bist, logge Dich jetzt ein.

Gast
Auf dieses Thema antworten...

×   Du hast formatierten Text eingefügt.   Formatierung jetzt entfernen

  Only 75 emoji are allowed.

×   Dein Link wurde automatisch eingebettet.   Einbetten rückgängig machen und als Link darstellen

×   Dein vorheriger Inhalt wurde wiederhergestellt.   Editor-Fenster leeren

×   Du kannst Bilder nicht direkt einfügen. Lade Bilder hoch oder lade sie von einer URL.

×
×
  • Neu erstellen...