mit sed von hinten?

P

plasma

Grünschnabel
hallo, ich bastel gerade an einem shellscript und bin auf ein problem gestoßen bei dem ich mir nicht sicher ob dies überhaupt möglich ist bzw ich überhaupt den richtigen ansatz habe.

also ich habe vor eine variable die einen namen mit a, e, i, oder o enthält so zu verändern, dass aus nur einen von den buchstaben, den ersten in der schleife getroffenen, von ende des wortes beginnend, eine 4, 3, 1, bzw 0 gemacht wird.

bei einem a wäre das z.B.
echo $name | sed s/a$/4/

das trifft ja aber nur das ende von der zeile. d.h. wenn der name nicht auf einen von den buchstaben endet scheitert meine schleife.
ist das irgendwie realisierbar?

bitte helft mir ich bin am verzweifeln :(
 
Muss es unbedingt mit sed sein?

edit: Ein Schnellschuss mit perl:

Code:
echo $name | perl -pe 's/^(.*)a/${1}4/'
 
Zuletzt bearbeitet:
Mit fällt da im Moment nur ... | sed 's/a$/4/; s/a /4 /' ... ein, um nach dem Leerzeichen oder dem Zeilenende zu suchen.
Nicht schön, aber selten :-)

Heiko
 
ja das hilft mir schonmal weiter xanti, danke.
ich habe bloß die befürchtung das nich auf jeder shell wo ich das script brauchen werde perl installiert ist.
also es gibt keine "nativere" lösung?

hwj: im prinzip wäre das in einer textdatei wo ich nach bestimmten wörtern suche bestimmt auch ne lösung, aber ich hab habe ja nur einen einzeiler, eine variable mit einem namen, die auch kein leerzeichen enthält

wenn noch jemand vorschläge hat immer her damit :)
 
Mein bescheidener Vorschlag:
echo $name | rev | sed -e 's/a/4/' | rev

Das erste "rev" dreht die Reihenfolge des Namens um (von ABCD in DCBA um), das sed tauscht den ersten Buschsteben/Zeichen (nach Wunsch) aus (nur wenn am Ende kein "g" wie 's/a/4/g' steht!) und das letzte "rev" tauscht alles wieder in die richtige Richtung um.

Edit:
Jenachdem wie Du das willst (hab ich in Deiner Beschreibung nicht richtig verstanden), kann man dann eine der beiden folgenden Varianten als Ausgangsbasis nehmen:

$ echo ABCAIOBHUOI | rev | sed -e 's/[a,A,i,I,o,O]/4/' | rev
ABCAIOBHUO4

echo ABCAIOBHUOI | rev | sed -e 's/[a,A]/4/' -e 's/[i,I]/4/' -e 's/[o,O]/4/' | rev
ABC4IOBHU44


Viel Spaß!
 
Zuletzt bearbeitet:
Hallo

Hab ich dich richtig verstanden, dass du nur den letzten buchtaben der Zeile ersetzen willst? :think:
a mit 4
e mit 3
i mit 1 nicht 2:think:
o mit 0

Dann würde ich das auch mit Perl machen.
Stichwort hash
Code:
echo testa|perl -ne 'BEGIN{%h=(a=>4,e=>3,i=>1,o=>0)}s/^(.*)(.)$/$1$h{$2}/;print'
Kann aber auch sein, dass ich dich total missverstanden habe.
Perl ist eigentlich auf fast jedem unixoiden System essentiell.
Die Kompatibilität von sed und der verwendeten Shell dagegen bei vielen Systemen eher unsicherer als Perl.

Gruß Wolfgang
 
Dafür braucht man kein Perl, das geht auch mit Boardmitteln!

das letzte "a"in eine "4" tauschen;
das letzte "e"in eine "3" tauschen;
das letzte "i"in eine "1" tauschen;
das letzte "o"in eine "0" tauschen;

(Ich verstehe jetzt den Sinn dieser Aktion! ;-)

# echo ABCAIOBHUOI | rev | sed -e 's/[a,A]/4/' -e 's/[e,E]/3/' -e 's/[i,I]/1/' -e 's/[o,O]/0/' | rev
ABC4IOBHU01


Edit:
(ein besseres Beispiel)

Nur das letzte Wort in der Zeile:
# echo "Alles klar auf der Andeadoria" | rev | sed -e 's/[a,A]/4/' -e 's/[e,E]/3/' -e 's/[i,I]/1/' -e 's/[o,O]/0/' | rev
Alles klar auf der And3ad0r14

Alle Worte in der Zeile:
# echo "Alles klar auf der Andeadoria" | tr -s ' ' '\n' | rev | sed -e 's/[a,A]/4/' -e 's/[e,E]/3/' -e 's/[i,I]/1/' -e 's/[o,O]/0/' | rev | tr -s '\n' ' '
4ll3s kl4r 4uf d3r And3ad0r14
 
Zuletzt bearbeitet:
Yoda schrieb:
Dafür braucht man kein Perl, das geht auch mit Boardmitteln!

das letzte "a"in eine "4" tauschen;
das letzte "e"in eine "3" tauschen;
das letzte "i"in eine "1" tauschen;
das letzte "o"in eine "0" tauschen;

(Ich verstehe jetzt den Sinn dieser Aktion! ;-)

# echo ABCAIOBHUOI | rev | sed -e 's/[a,A]/4/' -e 's/[e,E]/3/' -e 's/[i,I]/1/' -e 's/[o,O]/0/' | rev
ABC4IOBHU01
Ich habe die Aufgabe zwar anders verstanden, aber in diesem Fall kannst du dir zwei unnötige Prozesse sparen: wozu das rev? ;)
Code:
$ echo ABCAIOBHUOI |sed -e 's/^\(.*\)A\([^A]*\)$/\14\2/ig;s/^\(.*\)I\([^I]*\)$/\11\2/ig;s/^\(.*\)I\([^A]*\)$/\11\2/ig;s/^\(.*\)E\([^E]*\)$/\13\2/ig;s/^\(.*\)o\([^o]*\)$/\10\2/ig;'
ABC41OBHU01


Aber Vorsicht, sed ist nicht gleich sed.
Viele Wege führen nach Rom.
Gruß Wolfgang
 
Wolfgang schrieb:
Ich habe die Aufgabe zwar anders verstanden, aber in diesem Fall kannst du dir zwei unnötige Prozesse sparen: wozu das rev? ;)
Nein das ist zwingend nötig, da sed die Zeile immer von links nach rechts durcharbeitet. Er will aber das die letzten Buchstageb (die ersten von hinten) ausgetauscht werden. Also muss die Zeile umgedreht werden bevor sed sie bekommt und dann nach dem sed muss sie natürlich wieder richtig herum gedreht werden.
Wenn man dem sed am Ende noch ein "g" mit angibt (siehe mein Post weiter unten), dann tauscht er nicht nur das erste gefundene, sondern, alle aus. Nur in dem Fall kann man die rev weg lassen.

Wolfgang schrieb:
Aber Vorsicht, sed ist nicht gleich sed.
Viele Wege führen nach Rom.
Gruß Wolfgang
Das mag sein, aber die oben angeführten Optionen/Syntax funktioniert auf verschiedene Linux-Distrib., FreeBSD und NetBSD! Mit Sicherheit noch auf anderen, aber die nutze ich aber nicht.
 
Yoda schrieb:
Nein das ist zwingend nötig, da sed die Zeile immer von links nach rechts durcharbeitet. Er will aber das die letzten Buchstageb (die ersten von hinten) ausgetauscht werden. Also muss die Zeile umgedreht werden bevor sed sie bekommt und dann nach dem sed muss sie natürlich wieder richtig herum gedreht werden.
Wenn man dem sed am Ende noch ein "g" mit angibt (siehe mein Post weiter unten), dann tauscht er nicht nur das erste gefundene, sondern, alle aus. Nur in dem Fall kann man die rev weg lassen.


Das mag sein, aber die oben angeführten Optionen/Syntax funktioniert auf verschiedene Linux-Distrib., FreeBSD und NetBSD! Mit Sicherheit noch auf anderen, aber die nutze ich aber nicht.

Wie du aber oben sehen kannst, suche ich z.B. nach dem letzten A in der Zeile, indem ich nach irgendetwas gefolgt von A gefolgt von irgendetwas ausser A.
Dadurch erspare ich mir das rev und erwische das letzte a. Das i unterscheidet zusätzlich nicht zwischen A und a.
;)

Gruß Wolfgang
 
Wolfgang schrieb:
Wie du aber oben sehen kannst, suche ich z.B. nach dem letzten A in der Zeile, indem ich nach irgendetwas gefolgt von A gefolgt von irgendetwas ausser A.
Dadurch erspare ich mir das rev und erwische das letzte a. Das i unterscheidet zusätzlich nicht zwischen A und a.
;)

Gruß Wolfgang
Ja, richtig! :-)
Ich arbeite grundsätzlich nicht mit Perl (verschiedene persönliche Gründe => Meinungen => z.B. siehe auch Perl-Webseite "Verhalten unter Last" / aber das ist ein anderes Thema) und ausserdem wollte er ja ein sed-Kommando ("mit sed von hinten?").
:-)
 
Hallo
Ja, und zu dem Sedkommando habe ich auch ein Beispiel geschrieben.
Schau mal richtig hin. ;)
Code:
$ echo ABCAIOBHUOI |sed -e 's/^\(.*\)A\([^A]*\)$/\14\2/ig;s/^\(.*\)I\([^I]*\)$/\11\2/ig;s/^\(.*\)I\([^A]*\)$/\11\2/ig;s/^\(.*\)E\([^E]*\)$/\13\2/ig;s/^\(.*\)o\([^o]*\)$/\10\2/ig;'
ABC41OBHU01

Zum Thema Website kann ich in diesem Thread nix lesen.
Für die shell ist perl unverwüstlich schnell, schlank und sehr portierbarer Code!
Aber das wird hier OT

Gruß Wolfgang
 
Wolfgang schrieb:
Hallo
Ja, und zu dem Sedkommando habe ich auch ein Beispiel geschrieben.
Schau mal richtig hin. ;)
Code:
$ echo ABCAIOBHUOI |sed -e 's/^\(.*\)A\([^A]*\)$/\14\2/ig;s/^\(.*\)I\([^I]*\)$/\11\2/ig;s/^\(.*\)I\([^A]*\)$/\11\2/ig;s/^\(.*\)E\([^E]*\)$/\13\2/ig;s/^\(.*\)o\([^o]*\)$/\10\2/ig;'
ABC41OBHU01
Es muss nicht immer RegEx sein... :-)

Wolfgang schrieb:
Zum Thema Website kann ich in diesem Thread nix lesen.
Für die shell ist perl unverwüstlich schnell, schlank und sehr portierbarer Code!
Aber das wird hier OT

Gruß Wolfgang
Ich auch nochmal:
[OT]
Die Bourne SHell (/bin/sh) ist auf jedem Uni* und bei Perl fehlen immer gerade die Module, die man braucht (Murphies law). Deshalb empfehle ich als Scriptsprache sh oder tcl. TCL ist monolitisch, portabel (auch Windows), schnell und einfacher zu lernen als die meisten anderen Scriptsprachen. Wenn es eine Compilersprache sein soll empfehle ich Pascal, das gibt es auch für alle Systeme, es ist enfach zu lernen, bietet wesentlich weniger Fallstricke als C und Co. und kann auch alles. Wer beruflich programmiert, muss sich sowieso an die Firmenvorgaben halten (meistens => C/C++ und Java). Aber ich spreche ohnehin nur Hobbyisten gegenüber Empfehlungen aus. Perl ist nicht schlecht, es ist so verbreitet weil es die erste seiner Art war und ich habe mich damit vor Jahren auch mal mit befasst. Das macht es mir aber auch nicht sympatischer.
Ist aber alles nur meine persönliche Meinung...
[/OT]
:-)
 
Yoda schrieb:
Es muss nicht immer RegEx sein... :-)
hüstel...
Immerhin hast du auch RegExp verwendet. ;)

Man könnte das natürlich auch sehr umständlich mit Variablenexpansion der Bash hinbasteln.
Aber warum soll ich auf ein Werkzeug verzichten, wenn es mir die Arbeit erleichtert? :think:

Zu dem OT sag ich nix hier mal nix. ;)

Gruß Wolfgang
 
Wolfgang schrieb:
hüstel...
Immerhin hast du auch RegExp verwendet. ;)

Man könnte das natürlich auch sehr umständlich mit Variablenexpansion der Bash hinbasteln.
Aber warum soll ich auf ein Werkzeug verzichten, wenn es mir die Arbeit erleichtert? :think:

Zu dem OT sag ich nix hier mal nix. ;)

Gruß Wolfgang
Ich habe versucht sowohl die Vorgabe (sed zu verwenden) zu erfüllen als auch meinem eigenem Prinzip treu zu bleiben (mach es so einfach wie möglich).
Ich denke das ist mir gut gelungen:

# echo "Alles klar auf der Andeadoria" | rev | sed -e 's/[a,A]/4/' -e 's/[e,E]/3/' -e 's/[i,I]/1/' -e 's/[o,O]/0/' | rev
Alles klar auf der And3ad0r14

:-)
 
also vielen dank nochmal, ihr habt mir echt weitergeholfen und ich hab nun das ergebnis das ich wollte.
allerdings hat sich für mich dann ein weiterer haken offenbart, den ich so nich bedacht hatte.

meine schleife (ich weiß die is nich unbedingt notwendig) ersetzt ja nur in der vergegeben reihenfolge.
angenommen meine variable enthält den namen bzw das wort "blinder" und meine suchreihenfolge ist o, i, e und dann a, würde hier "bl1nder" rauskommen.
ich möchte ja aber den WIRKLICH ersten gefundenen, von mir definierten, buchstaben vom ende des wortes beginnend ersetzen, was in diesem falle das e wäre.

könnt ihr mir dafür bitte auch noch nen denkanstoß geben, wie sich das am besten realisieren lässt? ein freund empfahl mir awk, aber ich dachte das ist nur zur spaltenbearbeitung?
 
plasma schrieb:
also vielen dank nochmal, ihr habt mir echt weitergeholfen und ich hab nun das ergebnis das ich wollte.
allerdings hat sich für mich dann ein weiterer haken offenbart, den ich so nich bedacht hatte.

meine schleife (ich weiß die is nich unbedingt notwendig) ersetzt ja nur in der vergegeben reihenfolge.
angenommen meine variable enthält den namen bzw das wort "blinder" und meine suchreihenfolge ist o, i, e und dann a, würde hier "bl1nder" rauskommen.
ich möchte ja aber den WIRKLICH ersten gefundenen, von mir definierten, buchstaben vom ende des wortes beginnend ersetzen, was in diesem falle das e wäre.

könnt ihr mir dafür bitte auch noch nen denkanstoß geben, wie sich das am besten realisieren lässt? ein freund empfahl mir awk, aber ich dachte das ist nur zur spaltenbearbeitung?
also dafür muss ich auch erstmal etwas überlegen...
AWK kann viel, sehr viel! Es ist praktisch eine eigene komplette Scriptsprache. Damit kann man fast alles machen, leider behersche ich die nicht...
...von daher denke ich schon das man das Problem mit awk lösen kann.
Im Zweifelsfall kann Wolfgang ja wieder ein Monster-RegEx mit Voodoo fabrizieren... :-)


EDIT:
So, jetzt habe ich mal ein Script geschrieben => dirty hack

Es muss hier deutlich gesagt werden, das ich hier nicht den "Königsweg" zeige. Das ist nur ein Versuch, mit meinen bescheidenen Kenntnissen ans Ziel zu kommen!
Aber es funktioniert! :-)

Hinweis: In den zu filternden Worten oder Sätzen darf das hoch-drei-Zeichen (³) nicht enthalten sein, da ich es als internes "Erkennungszeichen" verwende. Du kannst es bei bedarf aber gegen ein beliegiges anderes einzelnes Zeichen austauschen, welches niemals in eines Deiner zu filternden Worte auftauchen wird.

Der Aufruf erfolgt für einen Satz so:
# sh das_erste_von_hinten.sh Alles klar auf der Andreadoria
Alles klar auf der Andreadori4

Der Aufruf erfolgt für ein einzelnes Wort so:
# sh das_erste_von_hinten.sh Andreadoria
Andreadori4

bzw. so:
# ./das_erste_von_hinten.sh Andreadoria
Andreadori4


# vi das_erste_von_hinten.sh
Code:
#!/bin/sh


### hier wird das auszutauschende Zeichen identifiziert
#   (damit die entsprechende Austauschroutine ausgewählt werden kann)
#
ZEICHEN="`echo "$@" | rev | sed -e 's/./&³/g' | tr -s '³' '\n' | sed -e 's/[A,E,I,O]/&³/i' | fgrep '³' | head -n1 | tr -d '³'`"


### hier geht es zur eigentlichen Arbeit,
### hier liegen die einzelnen möglichen routinen
#
case $ZEICHEN in
[Aa])
        ### hier wird das "A" ausgetauscht:
        echo "$@" | rev | sed -e 's/A/4/i' | rev
        ;;
[Ee])
        ### hier wird das "E" ausgetauscht:
        echo "$@" | rev | sed -e 's/E/3/i' | rev
        ;;
[Ii])
        ### hier wird das "I" ausgetauscht:
        echo "$@" | rev | sed -e 's/I/1/i' | rev
        ;;
[Oo])
        ### hier wird das "O" ausgetauscht:
        echo "$@" | rev | sed -e 's/O/0/i' | rev
        ;;
*)
        ### hier wird nichts ausgetauscht:
        echo "$@"
        ;;
esac
 
Zuletzt bearbeitet:
Zurück
Oben