glaskugel
Anmeldungsdatum: 8. Juli 2010
Beiträge: 3453
|
Meine Frage ergibt sich aus einem anderen Thread, ist aber allgemein zu beantworten. Das Ergebnis eines Scripts wird in eine Variable geschrieben und hat dann keine Zeilenumbrüche mehr und damit kann man nicht mehr "einfach" grep verwenden. Ich spiele mich schon einige Zeit und komme nicht weiter. var="### POINT START ### name=TP2639 latitude=49.6100383 longitude=6.1404299 elevation=273.0 time=2016-05-27 12:58:06 timezone_name=Europe/Luxembourg coordinates=49.6100383, 6.1404299 location=Batterie du Rham, Trierer Straße, Grund, Luxemburg, Kanton Luxemburg, 2427, Luxemburg licence=Data © OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright country_code3=LUX country_code=lu country=Luxemburg state= state_district= county=Kanton Luxemburg postcode=2427 city=Luxemburg town= suburb=Grund city_district= neighbourhood= road=Trierer Straße pedestrian= address29= path= house_number= townhall= ruins= attraction= place_of_worship= hotel= loc_name=Luxemburg street_name=Trierer Straße ### POINT END ###" Welche Möglichkeiten gibt es "49.6100383" herauszuholen? Als Annahme darf zuerst angenommen werden, dass das Leerzeichen Trenner zum nächsten Feld ist, obwohl das 1. Leerzeichen nicht immer Trenner ist. Ich denke es sollte mit sed -n möglich sein, stehe dabei aber an. Mit egrep geht es vermutlich auch. Komplizierter wird es um alles bis "location=" zu löschen und dann ab " licence=" Ich freue mich über Lösungsvorschläge.
|
track
Anmeldungsdatum: 26. Juni 2008
Beiträge: 7174
Wohnort: Wolfen (S-A)
|
glaskugel schrieb: Das Ergebnis eines Scripts wird in eine Variable geschrieben und hat dann keine Zeilenumbrüche mehr ...
Dann hast Du etwas falsch gemacht, vermutlich beim "Quoting" ! ... kann man nicht mehr "einfach" grep verwenden.
Doch, kann man, wenn man es richtig macht. Am einfachsten mit Perl-Lookaround:
track@track:~$ var="### POINT START ### name=TP2639 latitude=49.6100383 longitude=6.1404299 elevation=273.0 time=2016-05-27 12:58:06 timezone_name=Europe/Luxembourg coordinates=49.6100383, 6.1404299 location=Batterie du Rham, Trierer Straße, Grund, Luxemburg, Kanton Luxemburg, 2427, Luxemburg licence=Data © OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright country_code3=LUX country_code=lu country=Luxemburg state= state_district= county=Kanton Luxemburg postcode=2427 city=Luxemburg town= suburb=Grund city_district= neighbourhood= road=Trierer Straße pedestrian= address29= path= house_number= townhall= ruins= attraction= place_of_worship= hotel= loc_name=Luxemburg street_name=Trierer Straße ### POINT END ###"
track@track:~$ echo "$var" | grep -oP "(?<=latitude=).*(?= longitude=)"
49.6100383
track@track:~$ var1="${var##*latitude=}"
track@track:~$ echo "${var1%% longitude=*}"
49.6100383 Du siehst, auch mit 2 Parameter Expansions geht das genau so, wie Du schon sagtest: ... alles bis "location=" zu löschen und dann ab " licence="
LG, track
|
glaskugel
(Themenstarter)
Anmeldungsdatum: 8. Juli 2010
Beiträge: 3453
|
Dann hast Du etwas falsch gemacht, vermutlich beim "Quoting" !
Ja sieht so aus, bei echo muss man die Variable quoten, immer diese Schlamperei, wenn man testweise Variablen anzeigt 😉 Damit ist mein Problem vorläufig gelöst, ich würde aber gern dazu lernen und bei meiner Frage bleiben, wenn alles in 1 Zeile steht. Doch, kann man, wenn man es richtig macht. Am einfachsten mit Perl-Lookaround:
Darauf wurde ich dem anderen Thread auch schon hingewiesen, hatte da aber irgendeinen Fehler. echo "$var" | grep -oP "(?<=latitude=).*(?= longitude=)" Genau so funktioniert es bei mir nicht, da erhalte ich Zeilenumbrüche, so funktioniert es, da hat es keine Zeilenumbrüche: echo $var | grep -oP "(?<=latitude=).*(?= longitude=)" Nun stellt sich die Frage, ob es da etwas gibt, das in beiden Fällen das gewünschte bringt, egal ob gequotet oder nicht.
|
track
Anmeldungsdatum: 26. Juni 2008
Beiträge: 7174
Wohnort: Wolfen (S-A)
|
glaskugel schrieb: echo "$var" | grep -oP "(?<=latitude=).*(?= longitude=)" Genau so funktioniert es bei mir nicht, da erhalte ich Zeilenumbrüche
Aber dann ist doch mit Deiner Variablen eigentlich alles bestens, so wie es sein soll ! - die Zeilenumbrüche sind mit drin, und Du kannst alles perfekt trennen: | echo "$var" | grep -oP "(?<=latitude=).*"
|
also das komplette Ende der Zeile hinter dem Suchwort. Wahrscheinlich könntest Du die Daten sogar noch einfacher "ernten", wenn Du ein passendes Tool für die Originaldaten nimmst. In welchem Originalformat fallen die Daten denn ursprünglich an ? track
|
glaskugel
(Themenstarter)
Anmeldungsdatum: 8. Juli 2010
Beiträge: 3453
|
echo "$var" | grep -oP "(?<=latitude=).*" Was ist der Vorteil / Nachteil gegenüber: echo "$var" | grep "^latitude=" | cut -f2 -d"="
Aber dann ist doch mit Deiner Variablen eigentlich alles bestens, so wie es sein soll ! - die Zeilenumbrüche sind mit drin, und Du kannst alles perfekt trennen:
Ja, theoretisch passt es schon, ich will aber diese Problematik ein bisschen besser verstehen, wenn alles in 1 Zeile steht und es keine Alternative gibt.
Wahrscheinlich könntest Du die Daten sogar noch einfacher "ernten", wenn Du ein passendes Tool für die Originaldaten nimmst.
Sicherlich, das Problem ist aber komplexer. Es gibt verschiedene Server, die Geodaten anbieten und leider sind die Daten manchmal nicht nachzuvollziehen. Glücklicherweise hat sich da jemand um die Problematik bemüht und baut ein Python-Skript, wobei mein Problem ist, dass ich erst im Laufe der Zeit dahinter komme, was mir nicht so gefällt. Ich bin schon sehr froh, dass sich da jemand um die Thematik kümmert und was ich selber lösen kann, will ich ihn dann nicht mehr bemühen. Dafür will ich dann nicht jemand anderen beanspruchen. Hätte mir nicht gedacht, dass es ein Quoting-Problem ist. Ich zitiere mal, den Vorschlag vom anderen Thread, der bei mir nicht funktioniert. staat=$(grep -Po "(?<=^state=).*$" <<< $out) $out entspricht $var Ich wäre auch noch an der sed-Variante interessiert, falls die jemand weiß.
|
track
Anmeldungsdatum: 26. Juni 2008
Beiträge: 7174
Wohnort: Wolfen (S-A)
|
glaskugel schrieb: echo "$var" | grep -oP "(?<=latitude=).*" Was ist der Vorteil / Nachteil gegenüber: echo "$var" | grep "^latitude=" | cut -f2 -d"="
Das 1. ist übersichtlicher, finde ich, und es ist einfacher, weil es keinen 2. Befehl braucht. Rein praktisch geht natürlich beides. Du kannst Deine Variante auch schön in einem sed - Befehl oder einem awk - Befehl zusammenfassen: echo "$var" | sed -n '/^latitude="/ s/.*=//p'
echo "$var" | awk -F= '/^latitude="/ {print $2}' Wie die das genau machen, solltest Du mal im sed-Tutorium und in der awk-Einführung nachlesen. Überhaupt solltest Du unbedingt nachvollziehen, wie die einzelnen Vorschläge zu ihrem Ergebnis kommen. Dafür verlinke ich Dir ja schließlich die ganzen Hintergrund-Infos.
Ja, theoretisch passt es schon, ich will aber diese Problematik ein bisschen besser verstehen, wenn alles in 1 Zeile steht und es keine Alternative gibt.
Sobald Du den Kram mit echo $var (ohne "Quotes") ausgibst, steht er ja automatisch in 1 Zeile. Dafür hatte ich Dir ja oben meinen 1. Vorschlag gemacht. Also: siehe dort.
... Hätte mir nicht gedacht, dass es ein Quoting-Problem ist.
Dann lies bitte unbedingt nochmal den oben verlinkten Artikel zum "Quoting", und auch diesen Wiki-Artikel dazu. ... und probier doch einfach aus, was das echo $var ausgibt, mit und ohne "Quotes". Dann siehst Du es ja selber.
Ich zitiere mal, den Vorschlag vom anderen Thread, der bei mir nicht funktioniert. staat=$(grep -Po "(?<=^state=).*$" <<< $out)
Und ich bin mir ziemlich sicher, dass auch dieser Befehl funktioniert, sobald man ihn sauber "quotet": 😉
staat=$(grep -Po "(?<=^state=).*$" <<< "$out" )
LG, track
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11176
Wohnort: München
|
Ich habe das schon im anderen Thread angedeutet - mein Skript gibt die Werte zeilenweise aus, wenn der IFS unpassend gesetzt ist, liefert
| var=$(./geoinfo.py $ARGS)
|
natürlich nur schlecht verwertbaren Zeichensalat in einer Zeile.
Ich würde die Ausgabe entweder in eine (temporäre) Datei schreiben:
| ./geoinfo.py $ARGS > /tmp/geoinfo.tmp
grep -oP "(?<=^latitude=).*$" /tmp/geoinfo.tmp
|
oder den IFS passend setzen:
| IFS="" var=$(./geoinfo.py $ARGS)
grep -oP "(?<=^latitude=).*$" <<< "$var"
|
Edit: zu spät abgeschickt, ihr wart schon weiter...
|
glaskugel
(Themenstarter)
Anmeldungsdatum: 8. Juli 2010
Beiträge: 3453
|
Überhaupt solltest Du unbedingt nachvollziehen, wie die einzelnen Vorschläge zu ihrem Ergebnis kommen. Dafür verlinke ich Dir ja schließlich die ganzen Hintergrund-Infos.
Ja klar, habe ich mir auch angeschaut, bin aber zur Zeit sehr damit beschäftigt dieses Python-Script zu testen und da gibt es immer wieder Überraschungen, speziell wie man nicht erwartete Situationen abfangen kann. Ich versuche dazu auch einen Workaround, scheitere aber wieder mal an Regex & Co. Es geht um Suchen und löschen, wenn es gefunden wurde. zB var="123a,b,c,d456,e,4f" Ergebnis soll sein: ergebnis="b,c,e" Es gibt also Komma-getrennte Felder und falls eine Zahl irgendwie vorkommt, dann soll zwischen dem Komma gelöscht werden. Anfang und Ende haben kein Komma. Für mich schaut das nach einer Lösung mit sed aus.
|
track
Anmeldungsdatum: 26. Juni 2008
Beiträge: 7174
Wohnort: Wolfen (S-A)
|
glaskugel schrieb: ... Es gibt also Komma-getrennte Felder und falls eine Zahl irgendwie vorkommt, dann soll zwischen dem Komma gelöscht werden. Anfang und Ende haben kein Komma. Für mich schaut das nach einer Lösung mit sed aus.
Jo, wäre eine Möglichkeit. Grundsätzlich müsstest Du Dir also überlegen, wie Du so ein Feld mit einer RE beschreiben kannst. (Kleine Übersicht: hier und hier) Zuerst mal muss das Feld eine Ziffer enthalten: [0-9] Dann kann vorher sonstwas kommen, nur kein Komma (denn das wäre ja schon die Feldgrenze). Und dahinter das selbe: [^,]*[0-9][^,]* Das wäre so mal der Inhalt von einem Feld das weg soll. Sinnigerweise muss das "," dahinter auch mit weg, damit es nicht als Schusterjunge stehen bleibt. Und dann hat man noch das letzte Feld, hinter dem kein "," steht. Das stört natürlich, also schreibt man zuerst ein zusätzliches Komma dahinter und löscht es am Ende wieder weg. Dann passt der Filter auf alle Felder, auch auf das letzte: track@track:~$ echo "$var" | sed 's/$/,/; s/[^,]*[0-9][^,]*,//g; s/,$//'
b,c,e (der Modifier /g besorgt, dass dieser Filterteil generell auf alle passenden Felder angewandt wird) LG, track
|
glaskugel
(Themenstarter)
Anmeldungsdatum: 8. Juli 2010
Beiträge: 3453
|
Vielen Dank für die ausführliche und gute Erklärung! Ich habe mir in der Zwischenzeit was anderes überlegt. Die Sortierung war vorher nicht vorgegeben. echo "123a,b,c,d456,e,4f" | tr ',' '\n' | sort -f -u | grep -v '[0-9]' | tr '\n' ',' | sed 's/ *,//' Das darf gerne verbessert werden. Mich würde auch interessieren, ob das mit "grep \d" gelöst werden kann? echo "123a,b,c,d456,e,4f" | tr ',' '\n' | sort -f -u | grep \d
d456 echo "123a,b,c,d456,e,4f" | tr ',' '\n' | sort -f -u | grep -v \d
123a
4f
b
c
e
|
glaskugel
(Themenstarter)
Anmeldungsdatum: 8. Juli 2010
Beiträge: 3453
|
echo "123a,b,c,d456,e,4f" | tr ',' '\n' | sort -f -u | grep -v '[0-9]' | tr '\n' ',' | sed 's/ *,//'
bc,e, Ich sehe da gerade, da gibt es noch ein Problem, da fehlt nach b das Komma. Ich hatte da aus einer anderen Ersetzung was rein kopiert. So sollte es aber passen:
echo "123a,b,c,d456,e,4f" | tr ',' '\n' | sort -f -u | grep -v '[0-9]' | tr '\n' ',' | sed 's/,*$//'
b,c,e
|
glaskugel
(Themenstarter)
Anmeldungsdatum: 8. Juli 2010
Beiträge: 3453
|
Und da ist noch ein Problem aufgetaucht. Zum Verstöndnis, ich versuche Tags automatisch zu erzeugen. Nehmen wir an ich habe: var="1,abcde,fg,h,ij,k,lmno,pq" Nun möchte ich alles mit 1 und 2 Zeichen zwischen dem Komma eliminieren. Ergebnis soll also sein: ergebnis="abcde,lmno"
|
track
Anmeldungsdatum: 26. Juni 2008
Beiträge: 7174
Wohnort: Wolfen (S-A)
|
Fällt mir erstmal nur was mit einem Perl Lookaround ein. Dabei müsstest Du hilfsweise wieder vorne und hinten noch Kommas anstückeln, damit es auch für das erste und das letzte Feld klappt: track@track:~$ var=1,abcde,fg,h,ij,k,lmno,pq
track@track:~$ echo ,$var,
,1,abcde,fg,h,ij,k,lmno,pq,
track@track:~$ echo ,$var, | perl -pe 's/,..?(?=,)//g; s/,//; s/,$//'
abcde,lmno Perl hat den gleichen s-Befehl wie sed , nur mit noch mehr Möglichkeiten. LG, track p.s.: Aber du kommst hier jetzt nicht alle 3 Tage mit einem neuen Kniffel-Quiz, oder ? 😉
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11176
Wohnort: München
|
Man könnte auch mit einem angepassten IFS arbeiten, wenn man das mit den Mitteln der Bash erledigen möchte:
| var="1,abcde,fg,h,ij,k,lmno,pq"
ergebnis=$(IFS=','; for i in $var; do [ ${#i} -gt 2 ] && echo -n "$i,"; done | sed 's/,$//')
|
|