staging.inyokaproject.org

String in Datei1 finden und durch String aus Datei2 ersetzen

Status: Ungelöst | Ubuntu-Version: Kubuntu 22.04 (Jammy Jellyfish)
Antworten |

dafosy

Anmeldungsdatum:
26. Februar 2012

Beiträge: 116

Ein Hallo ins Forum,

ich habe folgende Herausforderung: auf meinem Router lasse ich YAMon3 laufen, ein Netzwerkanalyse-Hilfsmittel. Dort wird eine Teilnehmerliste der Netzwerkgeräte erstellt, in folgender Form (alle MACs sind frei erfunden):

Datei-neu.txt

ud_a({"mac":"16:9b:9f:d3:45:a7","ip":"192.168.0.126","ip6":"","owner":"Unknown","name":"New Device-02","colour":"","added":"2022-01-24 11:05:15","updated":"2023-02-23 13:31:27","last-seen":"2022-01-24 11:05:15"})
ud_a({"mac":"88:1a:a1:06:c1:65","ip":"192.168.0.124","ip6":"","owner":"Unknown","name":"New Device-03","colour":"","added":"2022-01-24 11:05:15","updated":"2023-02-27 23:57:18","last-seen":"2022-01-24 11:05:15"})

in der Vergangenheit habe ich die MAC-Adressen schon einmal zugeordnet und in einer anderen Datei in der Form, ähnlich dieser: Datei-alt.txt

ud_a({"mac":"16:9b:9f:d3:45:a7","ip":"192.168.0.168","ip6":"","owner":"AndrIVA","name":"iPhone","colour":"","added":"2021-12-02 09:52:38","updated":"2021-12-02 09:52:38","last-seen":"2021-12-02 09:52:38"})
ud_a({"mac":"88:1a:a1:06:c1:65","ip":"192.168.0.124","ip6":"","owner":"AndreaS","name":"Apple-TV","colour":"","added":"2021-12-02 22:10:39","updated":"2021-12-02 22:10:39","last-seen":"2021-12-02 22:10:39"})

Das Skript auf dem Router zerschießt mir gelegentlich meine Ordnung und da ist mein Plan ein einfaches bash zu bauen. Mittels sed, grep, cut, awk und Konsorten, welches in der Datei-neu.txt einen String sucht - hier bspw. eine MAC-Adresse, anschließend in die Datei-alt.txt nachschaut und von dort dann den String ab der gesuchten MAC-Adresse bis bspw. zum Muster "colour" den Inhalt übernimmt und in die Datei-neu.txt ersetzt.

Wie würdet ihr das machen?

Mein Ansatz ist aktuell: Datei-alt.txt soweit mit sed zerlegen, dass ich pro Zeile dann stehen habe:

16:9b:9f:d3:45:a7","ip":"192.168.0.168","ip6":"","owner":"AndrIVA","name":"iPhone"
88:1a:a1:06:c1:65","ip":"192.168.0.124","ip6":"","owner":"AndreaS","name":"Apple-TV"

Anschließend würde ich in Datei-neu.txt jeweils nach der MAC suchen und dann die Anweisung geben wollen, aus der umgewandelten Datei-alt.txt die komplette Zeile der dort jeweils am Zeilenanfang gefundenen MAC in die Datei-neu.txt zu übernehmen.

Hat jemand eine zündende Idee, wie ich das mache?

Grüße /dafosy

shiro

Anmeldungsdatum:
20. Juli 2020

Beiträge: 611

Da du Datei-neu.txt und Datei-alt.txt nach der MAC Adresse sortiert hast, funktioniert das wie folgt:

$ join -t'"' -j 4 -o 1.4,1.6,1.8,1.10,1.12,1.14,2.16,2.18,2.20 Datei-neu.txt Datei-alt.txt | sed 's/"/","/g;s/$/"/'
16:9b:9f:d3:45:a7","ip","192.168.0.126","ip6","","owner","AndrIVA","name","iPhone"
88:1a:a1:06:c1:65","ip","192.168.0.124","ip6","","owner","AndreaS","name","Apple-TV"

Zur Not musst du ein "sort" auf die MAC Adresse machen. Ob du die Felder 4-14 aus Datei 1 nimmst, musst du entscheiden.

Oops: Ich habe zu spät gesehen, dass du das Komma als Trennzeichen haben willst. In dem Fall wäre der Befehl:

$ join -t, -j 1 -o 1.1,1.2,1.3,2.4,2.5 Datei-neu.txt Datei-alt.txt | sed 's/^.*mac":"//'
16:9b:9f:d3:45:a7","ip":"192.168.0.126","ip6":"","owner":"AndrIVA","name":"iPhone"
88:1a:a1:06:c1:65","ip":"192.168.0.124","ip6":"","owner":"AndreaS","name":"Apple-TV"

dafosy

(Themenstarter)

Anmeldungsdatum:
26. Februar 2012

Beiträge: 116

Mega, das gucke ich mir heute gleich mal an.

dafosy

(Themenstarter)

Anmeldungsdatum:
26. Februar 2012

Beiträge: 116

Ich glaube join braucht den gleichen Dateiinhalt und ergänzt entsprechend Zeilenweise. Datei-neu.txt und Datei-alt.txt sind aber unterschiedlich lang, da in Datei-neu.txt natürlich auch die MAC Adressen, der sich neu angemeldeten Devices niederschlagen.

Auch probiere ich mal sort. Kann ich mit sort eigentlich nach erfolgter join-Routine auch wieder zurücksortieren lassen? Der letzte Eintrag einer jeden Zeile ist ja

..."last-seen":"2021-12-02 09:52:38"})

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 12527

Mein Ansatz wäre, mit Ruby die Dateien zu parsen (da gibt es z.B. ein JSON-Modul) und dann einen lookup zu machen und die entsprechende Zeile zu ersetzten. Habe nur gerade keine Zeit was zu basteln. So grob

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#!/usr/bin/ruby

require 'json'

# these should come via OptionParser from the command line
key = "mac"
value = "16:9b:9f:d3:45:a7"

old = []

File.foreach(ARGV.shift) do |line|
  json = line[/^[^(]+\((.*)\)\)$/, 1]
  old << JSON.parse(json)
end

File.foreach(ARGV.shift) do |line|
  json = line[/^[^(]+\((.*)\)\)$/, 1]
  record = JSON.parse(json)
  
  item = old.find do |r|
    r[key] == value
  end

  if item
    record.merge(item)
    puts("ua_(#{record.to_json})")
  else
    puts line
  end
end

ungetestet

shiro

Anmeldungsdatum:
20. Juli 2020

Beiträge: 611

dafosy schrieb:

Ich glaube join braucht den gleichen Dateiinhalt und ergänzt entsprechend Zeilenweise.

Nein. Der "join" Befehl verbindet z.B. 2 Dateien über einen gemeinsamen Key. Dieser Key ist in meinem Beispiel die MAC Adresse (das erste durch Komma separierte Feld: ud_a({"mac":"16:9b:9f:d3:45:a7"). Es muss nicht das erste Feld wie in deinem Beispieldatensatz sein. Wenn in beiden Dateien aber das erste Feld als Key verwendet wird, kann der Parameter "-j 1" verwendet werden. Dies ist gleichbedeutend mit "-1 1 -2 1". Die Anzahl der Felder (uns somit die Länge des Records ist irrelevant).

Die Felder, die du ausgeben möchtest, kannst du mit dem "-o" Parameter in der gewünschten Reihenfolge festlegen. Soll das Feld aus der ersten Datei genommen werden, so werden Datei und Feldnummer durch einen Punkt getrennt. Beispiel: Das 3. Feld der ersten Datei lautet dann "1.3", das 4. Feld aus der zweiten Datei lautet "2.4". Mit dem Parameter "-o 2.4,1.3" werden das 4. Feld aus der zweiten Datei gefolgt vom 3. Feld aus der ersten Datei durch das Trennzeichen (-t) getrennt ausgegeben.

Wenn du die neue Datei mit dem Feld "last-seen" ausgeben willst, solltest du das 9. Feld aus der ersten Datei (Datei-neu.txt) mit ausgeben lassen (d.h. 1.9), um danach sortieren zu können.

Beispiel:

$ join -t, -j 1 -o 1.1,1.2,1.3,2.4,2.5,1.9 Datei-neu.txt Datei-alt.txt | sed 's/^.*mac":"//;s/})$//' | sort -t, -k6
16:9b:9f:d3:45:a7","ip":"192.168.0.126","ip6":"","owner":"AndrIVA","name":"iPhone","last-seen":"2022-01-24 11:05:15"
88:1a:a1:06:c1:65","ip":"192.168.0.124","ip6":"","owner":"AndreaS","name":"Apple-TV","last-seen":"2022-01-24 11:05:15"
# Wenn "last-seen" aus der zweiten Datei (Datei-alt.txt), dann 
$ join -t, -j 1 -o 1.1,1.2,1.3,2.4,2.5,2.9 Datei-neu.txt Datei-alt.txt | sed 's/^.*mac":"//;s/})$//' | sort -t, -k6r
88:1a:a1:06:c1:65","ip":"192.168.0.124","ip6":"","owner":"AndreaS","name":"Apple-TV","last-seen":"2021-12-02 22:10:39"
16:9b:9f:d3:45:a7","ip":"192.168.0.126","ip6":"","owner":"AndrIVA","name":"iPhone","last-seen":"2021-12-02 09:52:38"

In obigem Beispiel ist die Ausgabedatei mit 6 Feldern durch Komma getrennt nach dem 6. Feld (last-seen) rückwärts sortiert (-k6r) worden. Wenn du vorwärts (aufsteigend) sortieren willst, machst du halt ein "-k6" (ohne "r").

Antworten |