linzus
Anmeldungsdatum: 31. Dezember 2015
Beiträge: 147
|
Hallo nochmal, ich habe ein weiteres Problem, bei dem ich leider selbst nicht mehr weiterkomme: wie im Bild zu sehen, hole ich mir die Vornamen aus der "xml" Datei, und speichere diese in dem Array namens "vornamen". Leider wird mir der Name "Heinz Felix" wegen des Leerzeichens dazwischen als 2 getrennte Namen eingetragen. Leider finde ich keine Lösung dies zu verhindern... Viele Grüße, ... PS: Ich hoffe diesmal passt meine Syntaktik
- Bilder
|
user_unknown
Anmeldungsdatum: 10. August 2005
Beiträge: 17620
Wohnort: Berlin
|
Du willst sicher nicht, dass wir das alle abtippen müssen, um damit rumzuexperimentieren. Weißt Du wie du Text unter Linux mit Mittelclick einfach kopieren kannst und hier in einen Codeblock einfügst?
|
linzus
(Themenstarter)
Anmeldungsdatum: 31. Dezember 2015
Beiträge: 147
|
user_unknown schrieb: Du willst sicher nicht, dass wir das alle abtippen müssen, um damit rumzuexperimentieren. Weißt Du wie du Text unter Linux mit Mittelclick einfach kopieren kannst und hier in einen Codeblock einfügst?
dachte das wäre so einfacher...hier der Quelltext: Datei: <?xml version="1.0" encoding="UTF-8"?>
<customers>
<person firstname="Heinz Felix" lastname="Hinterhuber" birthday="12.12.1929"/>
<person firstname="Erna" lastname="Etepetete" birthday="19.02.1997"/>
<person firstname="Kevin" lastname="Miller" birthday="20.10.1988"/>
<person firstname="Hugo" lastname="Helmchen" birthday="04.01.2145"/>
<person firstname="Rodolf" lastname="Reindeer" birthday="01.08.1939"/>
<person firstname="James" Lastname="Bond" birthday="11.11.1921"/>
</customers> Quellcode: #!/bin/bash
vornamen=($(head -8 xml | tail -6 | cut -d\" -f2))
|
user_unknown
Anmeldungsdatum: 10. August 2005
Beiträge: 17620
Wohnort: Berlin
|
IFS ist input field seperator o.s.ä., oifs ist der Old-IFS, sed -n verhindert die Ausgabe von Zeilen die nicht auf 'firstname...lastname' passen,
| oifs=$IFS
IFS=","
vornamen=($(sed -n 's/.*firstname="//;s/" lastname.*/,/p;' customers.xml))
echo ${vornamen[0]}
Heinz Felix
IFS=$oifs
echo ${vornamen[2]}
Kevin
|
Das mit dem IFS habe ich als heikel erlebt, weil man u.U. den alten nicht gut restaurieren kann, wenn man ihn nicht abgespeichert hat - genaueres kann ich aber nicht sagen. Manpage lesen. Viele Ritter der XML-Nuss behaupten man solle keinesfalls sed und auf jeden Fall xmlstarlet o.ä. benutzen, um XML zu parsen. In der Regel bringen sie auch wenige Tage später eine Lösung hin. Die erheiternden Diskussionen dazu lassen sich vielleicht mit Google finden.
|
anrub
Anmeldungsdatum: 4. Januar 2013
Beiträge: 336
|
Fragil bleibt die Lösung dennoch, da die Reihenfolge der Attribute im XML Element fest sein muss. D.h. falls zufällig mal lastname vor dem firstname im Element steht - was in XML ja valide ist - funktioniert die Sache nicht mehr.. Oder falls im Vornamen ein Komma auftritt. Daher der Hinweis auf XML Parser. Ich würde es auch eher in einer anderen Sprache lösen, wie z.B. python, perl, groovy... Grüße
anrub
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 13205
|
anrub schrieb: Fragil bleibt die Lösung dennoch, da die Reihenfolge der Attribute im XML Element fest sein muss. D.h. falls zufällig mal lastname vor dem firstname im Element steht - was in XML ja valide ist - funktioniert die Sache nicht mehr.. Oder falls im Vornamen ein Komma auftritt.
Ja, man sollte da lieber Werkzeuge verwenden, die mit XML ordentlich umgehen können.
Daher der Hinweis auf XML Parser. Ich würde es auch eher in einer anderen Sprache lösen, wie z.B. python, perl, groovy...
... oder Ruby mit Nokogiri, genau. 👍
|
track
Anmeldungsdatum: 26. Juni 2008
Beiträge: 7174
Wohnort: Wolfen (S-A)
|
+1 Auch ich plädiere für XML- Werkzeuge, alles andere ist "bricolage", die vielleicht funktioniert, aber nicht wirklich stabil ist. Als Trennzeichen würde ich hier den TAB vorschlagen: der kommt in Namen ziemlich sicher nicht vor, und er liest sich gut, beim debuggen. Mit xmlstarlet ginge das z.B. so: track@track:~$ xmlstarlet sel -t -m //person -v @firstname -o "	" -v @lastname -n test_namen.xml
Heinz Felix Hinterhuber
Erna Etepetete
Kevin Miller
Hugo Helmchen
Rodolf Reindeer
James Du siehst auch, dass der Nachname "Last" dort fehlt, weil der Tag ein großes "L" hat. → passt also nicht. Das könntest Du jetzt (mit IFS='$\t') in ein Bash-Array einlesen, dazu gibt Greg gute Hinweise auf seinem Wiki. Aber sinnvoller ist wahrscheinlich wirklich eine andere Sprache, wie schon gesagt (nur würde ich aus alter Verbundenheit wohl awk nehmen 😉 ). Es kommt halt darauf an, was Du weiter damit vor hast ... LG, track
|
linzus
(Themenstarter)
Anmeldungsdatum: 31. Dezember 2015
Beiträge: 147
|
Vielen Dank für eure Antworten.
Leider sollen wir laut Vorgabe nur primitive Befehle benutzen, und sed, awk, usw. sind ausgeschlossen...
ich habe jetzt mal noch ein bisschen rumprobiert. Dabei bin ich auf die Option -F für grep gestoßen. -F --fixed-strings interpretiert das übergebene Muster als eine Liste von festen Zeichenketten, die durch Zeilenumbrüche voneinander getrennt sind. ich habe es jetzt mla probiert mit: | head -8 xml | tail -6 | cut -d⁄" -f2 | grep -F [a-zA-Z⁄ ]*
|
bis vor grep passt auch alles prima, ich bekomme die Namen ausgegeben in verschiedenen Zeilen. Leider weigert sich grep hartnäckig, mir irgendetwas auszugeben, auch wenn ich einfach nur .* schreibe, was ich nicht verstehe.
Gerade die Option -F wäre ja die perfekte Lösung: ich könnte einfach immer nur eine Zeile auswählen, und danach den ganzen String bis zum Zeilenumbruch in die Variable schreiben, wenn grep nur etwas ausgeben würde...
Hat vielleicht jemand einen Tip?
Viele Grüße,
... Bearbeitet von rklm: Codeblock
|
track
Anmeldungsdatum: 26. Juni 2008
Beiträge: 7174
Wohnort: Wolfen (S-A)
|
Ich verstehe nicht ganz, was Du da machst ... Ok, dass Dein Ausbilder sowas hirniges wie XML parsen mit grep verlangt, sowas ist zwar fachlich ein No-Go, kommt aber vor. Und man kann nichts dagegen machen, denn er ist schließlich der Chef. (n.b.: in einem vorigen Leben war ich selber mal Ausbilder für Computerklempner. 😀 ) Aber warum wählst Du die Zeilen mit head / tail aus, und nicht anhand der Tags am Zeilenanfang ? - das käme einem Parser immer noch am nächsten. Damit bekäme ich schon mal: track@track:~$ grep '<person ' test.xml
<person firstname="Heinz Felix" lastname="Hinterhuber" birthday="12.12.1929"/>
<person firstname="Erna" lastname="Etepetete" birthday="19.02.1997"/>
<person firstname="Kevin" lastname="Miller" birthday="20.10.1988"/>
<person firstname="Hugo" lastname="Helmchen" birthday="04.01.2145"/>
<person firstname="Rodolf" lastname="Reindeer" birthday="01.08.1939"/>
<person firstname="James" Lastname="Bond" birthday="11.11.1921"/>
track@track:~$ grep '<person ' test.xml | cut -d\" -f2
Heinz Felix
Erna
Kevin
Hugo
Rodolf
James Ist doch schon mal nicht schlecht, jeder Vorname in einer eigenen Zeile. Jetzt musst Du das Array nur noch überreden, nur den Zeilenumbruch als Trenner zu akzeptieren. Das Zauberwort für das Einlesen eines Arrays mit Hilfe der Klammer var=(... ... ...) ist Word splitting. Das ist es nämlich, was die Shell mit dieser "Zeile" macht, bevor sie an das Array verfüttert wird. Und in der Praxis musst Du genau daran drehen, damit eben nur noch das '\n' als Worttrenner genommen wird. (Das zeige ich Dir hier jetzt aber nicht, sondern das musst Du selber nachlesen und rausfinden ! 😉 ) LG, track
|
user_unknown
Anmeldungsdatum: 10. August 2005
Beiträge: 17620
Wohnort: Berlin
|
Es ist ganz leicht. Zeilenumbruch ist das neue Komma:
| oifs=$IFS
IFS="
"
vns=($(grep person customers.xml | cut -d\" -f 2))
echo ${vns[0]}
echo ${vns[@]}
IFS=$oifs
|
Die Bedenken bzgl. XML sind m.E. maßlos übertrieben. Oft produziert man das XML selbst, und hat in der Hand, wie es geschrieben wird, oder es kommt von einem Gerät, das auch nicht magisch den Output ändert. Selbst wenn sich was ändert muss das Programm nicht leiden und wenn doch, dann ist so ein Minicode schneller gefixt man 'man xmlstarlet' sagen kann. Außerdem sind jede Menge Änderungen des XML-Codes denkbar, die ebenfalls zum Versagen führen können - eine Sicherheitsgarantie bildet das also auch nicht. Beispielsweise könnte jmd. das XML von Hand schreiben, und Lastname statt lastname schreiben. 😉
|
linzus
(Themenstarter)
Anmeldungsdatum: 31. Dezember 2015
Beiträge: 147
|
Hallo track und user_unknown,
vielen Dank für eure Hilfe!
Es funktioniert tatsächlich! ☺
die Sache mit dem IFS und dem wordsplitting war mir vorher überhaupt nicht bekannt. Das hat mir enorm geholfen, und jetzt verstehe ich auch was da passiert.
2 Kleinigkeiten habe ich jetzt noch: user_unknown hat den IFS ja mit:
IFS="
"
festgelegt. Da ich selbst noch recherchiert habe, bin ich auf die Festlegung des IFS mit
IFS="$(printf '\n')"
gestoßen.
Lege ich den IFS allerdings damit fest, habe ich wieder das gleiche Problem mit der Zuweisung. Mit
IFS="$(printf \n)"
demaskiert er das n, was die Sache noch schlechter macht ☺ Ich habe nachgelesen was " " und ' ' eigentlich bewirken. Soweit ich es verstanden habe, sollte " " die Bash überreden die Eingabe als string anzusehen und Steuerzeichen zu ignorieren, während ' ' Steuerzeichen zulässt. Demnach müsste die erste Belegung des IFS oben doch aber auch funktionieren, oder? Und was ich nicht verstehe ist das
printf "\n"
mir in der bash prima eine leere Zeile ausgibt (also wurde das Steuerzeichen offenbar korrekt gelesen), in der Einbettung wie oben dann aber einen Fehlerhaften Wert zurückgibt. Ich vermute es liegt an den Klammern ( ) verstehe aber nicht genau wieso. Was genau bewirken die Klammern denn in der Bash? z.B. auch hier:
vns=($(grep person customers.xml | cut -d\" -f 2))
wieso werden links vor dem $-Zeichen nochmals Klammern benötigt? Vielen Dank und Grüße,
...
|
track
Anmeldungsdatum: 26. Juni 2008
Beiträge: 7174
Wohnort: Wolfen (S-A)
|
Du scheiterst hier an einer Tücke der Command Substitution. (Mit dem Quoting hat das also alles nichts zu tun !) Dort heißt es: substituted ... with any trailing newlines deleted.
Auf diesem Wege bekommst Du Deinen Zeilenumbruch also nicht in die Variable. Entweder Du schreibst ihn direkt, wie user_unknown, oder Du benutzt ANSI-C-Quoting:
IFS=$'\n'
Edit: wieso werden links vor dem $-Zeichen nochmals Klammern benötigt?
Dabei geht es um das Array. Bitte lies noch einmal den Artikel auf Greg's Wiki dazu. Ich hatte ihn oben schon verlinkt. LG, track
|
linzus
(Themenstarter)
Anmeldungsdatum: 31. Dezember 2015
Beiträge: 147
|
track schrieb: Du scheiterst hier an einer Tücke der Command Substitution. (Mit dem Quoting hat das also alles nichts zu tun !) Dort heißt es: substituted ... with any trailing newlines deleted.
Auf diesem Wege bekommst Du Deinen Zeilenumbruch also nicht in die Variable. Entweder Du schreibst ihn direkt, wie user_unknown, oder Du benutzt ANSI-C-Quoting:
IFS=$'\n'
Edit: wieso werden links vor dem $-Zeichen nochmals Klammern benötigt?
Dabei geht es um das Array. Bitte lies noch einmal den Artikel auf Greg's Wiki dazu. Ich hatte ihn oben schon verlinkt. LG, track
Alles klar, vielen Dank. den Link oben hatte ich ganz übersehen Viele Grüße, ...
|