Categories
PowerShell Windows

Mehrfache Einträge in großen Konfigurationsdateien oder Protokollen finden (Windows Powershell Lösung)

Im Post Mehrfache Einträge in großen Konfigurationsdateien oder Protokollen finden(Linux/Unix) habe ich gezeigt, wie mehrfach vorkommende Zeilen in Textdateien gefunden und automatisch entfernt werden können.
Windows hat im Zuge der Powershell ein mächtiges Werkzeug, dass dies auch kann. (Seit dem Windows 10 1709 Update kann man natürlich auch einfach die eingebaute bash nehmen….)

Zur Demonstration verwende ich eine Datei duplicates.txt:

Get-Content -Path duplicates.txt

Zeile kommt nur einmal vor
Zeile kommt zweimal vor
Zeile kommt dreimal vor
Zeile kommt zweimal vor
Zeile kommt dreimal vor
Zeile kommt auch nur einmal vor
Zeile kommt dreimal vor

Mehrfache vorkommende identische Zeilen und deren Anzahl findet und zählt man wie mit Group-Object

Get-Content -Path duplicates.txt |Group-Object

Count Name Group
—– —- —–
1 Zeile kommt nur einmal… {Zeile kommt nur einmal vor}
2 Zeile kommt zweimal vor {Zeile kommt zweimal vor, Zeile kommt zweimal vor}
3 Zeile kommt dreimal vor {Zeile kommt dreimal vor, Zeile kommt dreimal vor, Zeile kommt dreimal vor}
1 Zeile kommt auch nur e… {Zeile kommt auch nur einmal vor}

Wenn die Reihenfolge der Zeilen keine Bedeutung hat, ist es einfach, doppelte oder mehrfache Zeilen zu entfernen:

Get-Content -Path duplicates.txt | Sort-object -Unique

Zeile kommt auch nur einmal vor
Zeile kommt dreimal vor
Zeile kommt nur einmal vor
Zeile kommt zweimal vor

oder

Get-Content -Path duplicates.txt | sort-object | Get-Unique

Zeile kommt auch nur einmal vor
Zeile kommt dreimal vor
Zeile kommt nur einmal vor
Zeile kommt zweimal vor

Die Ausgabe aller mehrfach vorkommenden Zeilen kann mit einer einfachen Abfrage geschehen:

Get-Content -Path duplicates.txt | Group | ? { $_.Count -gt 1 } |Select -ExpandProperty Name

Schwieriger wird es, die doppelten Zeilen zu entfernen, wenn die Reihenfolge in der Datei erhalten bleiben soll. Eine Hash Tabelle hilft an dieser Stelle weiter. Die zugrunde liegende Idee ist, für jede Zeile beim ersten Auftreten einen Eintrag in einer Hashtabelle vorzunehmen. Sollte dieser Zeile erneut auftreten, wird sie übersprungen. Das ist der Code:

$hash = $null
$hashTable = @{}
Get-Content .\duplicates.txt | ForEach-Object {
  if ($hashTable.Item($_) -eq $null) {
    $_
    $hashTable.Add($_,”found”)
  }
}

Zeile kommt nur einmal vor
Zeile kommt zweimal vor
Zeile kommt dreimal vor
Zeile kommt auch nur einmal vor

Die ersten beiden Zeilen initialisieren die Tabelle $hashTable. Dann wird für jede neue Zeile ein Eintrag mit dem Wert “found” hinzugefügt (eine 1, ein true oder ähnlich würden es auch tun, Hauptsache ein Eintrag für die Zeile existiert.).

Achtung: Die Ausgabe von $hashTable.Keys gibt die Reihenfolge nicht wie in der Datei aus:

$hashTable.Keys

Zeile kommt dreimal vor
Zeile kommt zweimal vor
Zeile kommt nur einmal vor
Zeile kommt auch nur einmal vor

Sehr hilfreich sind die Erklärungen zu Powershell Hash Tabellen von den Scripting Guys.

Categories
Korn Shell / Bash Shell Programmierung

Mehrfache Einträge in großen Konfigurationsdateien oder Protokollen finden (Linux/Unix Lösung)

Oft vermutet man in größeren Protokolldateien oder Konfigurationsdateien mehrfach vorhandene Einträge. Diese sollen schnell ermittelt und bei Bedarf entfernt werden.
Unter Linux gibt es das Werkzeug uniq. Der Parameter --count gibt alle Zeilen aus und die Häufigkeit Ihres Auftretens in der ersten Spalte. Es funktioniert nur nicht so intuitiv, wie erwartet. Ich versuche es an einem Beispiel:

uniq –count console.log

1 <?xml version=”1.0″ encoding=”UTF-8″ ?>
1 <Protokollzeile xxxyyyzzz >

Diese Datei hat offensichtlich zwei Zeilen insgesamt und beide unterscheiden sich. Das ist im Moment nicht sehr hilfreich. Daher verdoppele ich die Datei und füge eine einzeln vorkommende Zeile hinzu:

cat console.log >> consoleDup.log
cat console.log >> consoleDup.log
echo “Eine abweichende Zeile >> consoleDup.log

Eine erneute Überprüfung mit uniq zeigt das Problem:

uniq –count consoleDup.log

1 <?xml version=”1.0″ encoding=”UTF-8″ ?>
1 <Protokollzeile xxxyyyzzz >
1 <?xml version=”1.0″ encoding=”UTF-8″ ?>
1 <Protokollzeile xxxyyyzzz >
1 Eine abweichende Zeile

Genau, das wollten wir so nicht sehen. Die erste und dritte Zeile und die zweite und vierte Zeile sind identisch. Da sollte eine 2 stehen.
Aus dem gleichen Grund funktioniert uniq --unique nicht, solange die Datei nicht sortiert vorliegt. In den meisten Fällen (XML, JSON etc) Dazeien würde die Sortierung die Datei unbrauchbar machen.

Zur Lösung des Problems müssen die Zeilen sortiert werden.

sort consoleDup.log|uniq –count

1 Eine abweichende Zeile
2 <?xml version=”1.0″ encoding=”UTF-8″ ?>
2 <Protokollzeile xxxyyyzzz >

Schon besser. Der uniq Parameter --repeated gibt nur die mehrfach vorkommenden Zeilen aus:

sort consoleDup.log|uniq –count –repeated

2 <?xml version=”1.0″ encoding=”UTF-8″ ?>
2 <Protokollzeile xxxyyyzzz >
Doppelt oder noch häufiger vorkommende Zeilen in Textdaten können schnell und elegant mit awk entfernt werden:

awk ‘!seen[$0]++’ consoleDup.log >> console_noDupRecords.log
cat console_noDupRecords.log

<?xml version=”1.0″ encoding=”UTF-8″ ?>
<Protokollzeile xxxyyyzzz >

Eine Lösung für die Powershell zeige ich hier.

Categories
Korn Shell / Bash Shell Programmierung

Sehr nützliche grep Funktionen

grep wird von Linuxx/Unix Administratoren zwar sehr oft genutzt, einige sehr mächtige Optionen werden aber zu Unrecht wenig genutzt oder sind den Administratoren nicht bekannt.

1. Zeilen vor und nach der Fundstelle des Suchbegriffs ausgeben.
grep bietet die äusserst nützliche Funktion, Zeilen vor und nach dem gefundenen Suchbegriff anzuzeigen.

Um die Funktionen der grep Optionen darzustellen, verwende ich als Beispiel ein IBM Skript mit folgendem Inhalt, das von grep durchsucht wird:

cat collector.sh

#!/bin/sh
binDir=`dirname ${0}`
. ${binDir}/setupCmdLine.sh
${WAS_HOME}/bin/collector.sh “$@”

Die Option -A zeigt n Zeilen nach der Fundstelle an.

grep -A 1 setup collector.sh

. ${binDir}/setupCmdLine.sh
${WAS_HOME}/bin/collector.sh “$@”

Die Option -B zeigt n Zeilen vor der Fundstelle an.

grep -B 1 setup collector.sh

binDir=`dirname ${0}`
. ${binDir}/setupCmdLine.sh

Die Option -C zeigt n Zeilen vor und nach der Fundstelle an.

grep -C 1 setup collector.sh

binDir=`dirname ${0}`
. ${binDir}/setupCmdLine.sh

2. Farbliches Hervorheben des Suchbegriffs in den Fundstellen
grep kann in einem Terminal den gefundenen Suchbegriff farblich hervorheben. Dazu setzt man die Umgebungsvariable GREP_OPTIONS wie folgt:

export GREP_OPTIONS='--color=auto'

–color=always

wird oft in Blogs erwähnt, aber grep soll die Farben ja nur in interaktiven Terminals hervorheben. Daher empfehle ich die Option --color=auto. Am besten setzt man diese Umgebungsvariable in den Login Dateien (z.B. .bashrc).

3. Nur den Dateinamen mit der Fundstelle bei Suchen in mehreren Dateien ausgeben
grep ermöglicht Suchen in mehreren Dateien und auch rekursiv (Option -r) in Unterverzeichnissen. Wenn der Suchbegriff in vielen Dateien an mehreren Positionen enthalten ist, wird das Ergebnis
schnell unübersichtlich. Die grep Option -l bietet sich in diesen Fällen an. Sie gibt nicht die Zeile mit der Fundstelle aus, sonder zeigt nur den Dateinamen an.

grep -rl suchstring *

Categories
Shell Programmierung

awk – Ändern der Großschreibung in Kleinbuchstaben

Die Funktion tolower in einem awk Skript ändert Grossbuchstaben in Kleinbuchstaben:

awk '{ print tolower($0) }'

Die Funktion toupper in einem awk Skript ändert Grossbuchstaben in Kleinbuchstaben:

awk '{ print toupper($0) }'

Beispiel für AWK Funktion tolower

In diesem Beispiel soll das erste Feld in Kleinbuchstaben ausgegeben werden.

echo ABCDEF GHIJK | awk '{ print tolower($1), $2 }'

abcdef GHIJK

Beispiel für AWK Funktion toupper

In diesem Beispiel soll das erste Feld in Kleinbuchstaben ausgegeben werden.

echo abcdef ghijk | awk '{ print toupper($1), $2 }'

ABCDEF ghijk