bash: function die eine Zeile modifiziert

  • Hallo zusammen,


    ich möchte eine bash function schreiben, die folgendes leistet:


    Eingabe:
    Parameter 1: Erkennungs-Muster
    Parameter 2: Neue-Zeile String
    Parameter 3: Pfad und Dateiname


    Ausgabe:
    In der angegebenen Datei (Parameter 3) wird jede Zeile, die nicht mit # beginnt, und das Texterkennungsmuster enthält durch die neue Zeile (Parameter 2) ersetzt.


    Ich glaube, die entspechenden Zeilen sogar schon zu haben, muss sie aber noch zusammenfügen und testen. Ich werde sie dann posten.


    Aber ich vermute, meine Zeilen sind wiedereinmal suboptimal. Über Vorschläge wäre ich daher sehr dankbar. :]


    Gruß
    Wicky

  • So hier ist dann der erste Entwurf:



    Das Skript funktioniert, es hat aber noch eine nicht gewollte Einschränkung:
    -> Der Searchstring muss sich am Anfang der zu modifizierenden Zeilen befinden.


    Ich arbeite weiter.


    Gruß
    Wicky


    P.S. Ich möchte sehr ungern Perl in einem Bash Script verwenden.

  • Und schon eine Vereinfachung:



    Gruß
    Wicky

  • ääätsch, erster !!



    Diese Funktion scheint meine Anforderungen zu erfüllen. Ich muss aber noch ein bisserl testen.


    Eventuell sollte man auch noch ein paar Zustätliche Schalter hinzufügen...


    Gruß
    Wicky

  • So sollte es aber klappen (bei meiner Testdatei geht es zumindestens):

    Wichtig:
    Sed-Aufruf nicht verändern (auch keine Tabs o.ä. !).
    Beim Aufruf 'Erkennungs-Muster' und 'Neue-Zeile String' quoten (' oder evtl. ").

    Gruss
    SHF


  • Hi Wicky,


    probiers doch mal so:


    Bash
    #!/bin/sh
    awk '{
        if (match($0, "^('$1'|[^#].*'$1')")) print "'$2'"; else print
    }' < $3


    das Quoting ist evtl. noch nicht optimal. Genuegt das deinen Anforderungen? Das '#' muss
    hier wirklich als erstes Zeichen in der Zeile stehen, um als solches erkannt zu werden. Aber das war ja so gewollt?


    sparkie

  • SHF


    Wow, die Funktion scheint genau so zu funktionieren, wie ich es mir vorgestellt habe. Auch wenn ich sie noch nicht verstehe. :rolleyes:


    sparkie
    Deine Lösung sieht kürzer aus. Ich habe sie aber noch nicht getestet.


    @all


    Warum funktioniert eigentlich dieses Skript nicht, wenn der neue String ein Leerzeichen enthält?

    Gruß
    Wicky

  • Wicky


    aha! ich habe jetzt aus deinen obigen Postings gelernt, dass auch Leerzeichen funktionieren sollen und habe deswegen umgehend nachgebessert:


    Bash
    #!/bin/sh
    awk '{
        if (match($0, "^('"$1"'|[^#].*'"$1"')")) print "'"$2"'"; else print
    }' < $3
  • Zitat

    Original von sparkie
    Wicky


    aha! ich habe jetzt aus deinen obigen Postings gelernt, dass auch Leerzeichen funktionieren sollen und habe deswegen umgehend nachgebessert:


    Bash
    #!/bin/sh
    awk '{
        if (match($0, "^('"$1"'|[^#].*'"$1"')")) print "'"$2"'"; else print
    }' < $3


    Hi sparkie,


    das Skript scheint prinzipiell auch zu funktionieren, jedoch gibt es nur auf der Konsole aus und ändert nicht die Datei.


    Gruß
    Wicky

  • Zitat

    Original von sparkie
    besser?

    Bash
    #!/bin/sh
    awk '{
        if (match($0, "^('"$1"'|[^#].*'"$1"')")) print "'"$2"'"; else print
    }' < $3 > $3.$$
    cp $3.$$ $3; rm -f $3.$$


    JAAA, das sieht besser aus. Ich werde es dann morgen mal testen.
    Ich vermute, dass es funktionieren wird.


    Und da ich ja nun dankenswerter Weise zwei Lösungen von euch beiden erhalten habe, werde ich mal time darauf los lassen.


    Gruß und Danke,
    Wicky

  • Jungs, wieso benutzt ihr eigentlich für solche einfachen Zwecke nicht die in der Bash eingebauten Funktionen, sondern haut gleich mit Vorschlaghämmern wie sed und awk drauf, wo ihr euch zu allem Überfluss auch noch Quoting-Probleme einhandelt?


    Die Funktion lautet: ${Variable/Search/Replace}


    Einzelne Zeilen liest man mit "read" ein, anschließend bearbeitet man sie und gibt sie mit "echo" wieder aus -- wobei man sinnvollerweise in eine neue Datei schreibt, die man später umbenennt, damit man sich nicht den Ast absägt auf dem man sitzt. Natürlich kann man auch erst alle Zeilen einlesen, sie dann konvertieren und zum Schluss wieder ausgeben -- dann braucht man keine temporäre Datei.


    Achja, vergesst nicht die Variable IFS -- die sorgt dafür, dass ihr rein gar nichts quoten müsst, wenn sie lediglich das Newline enthält und nicht Space, Tab und Newline wie üblich.


    Viele Grüße, Mirko

  • Ich hab's eben nochmal probiert und es geht auch in einer Zeile:

    Code
    sed -i "/^[ tab]*\#/!{/^.*${1}/s/\(.*\)/${2}/}" ${3}

    Laut meinem Buch soll das zwar nicht gehen, aber es klappt doch. Auch dieses HOWTO gibt es auch in einer Zeile an. ... ich denke ich sollte mal in ein neueres Buch investieren.


    Zitat

    Original von Wicky
    Warum funktioniert eigentlich dieses Skript nicht, wenn der neue String ein Leerzeichen enthält?

    Ein Grund ist zumindestens, dass $ar, ${arg[1]} und ${arg[1]} nicht gequoted (..."$ar"...) sind.

    Gruss
    SHF


    Einmal editiert, zuletzt von SHF ()

  • Zitat

    Original von SHF


    Ein Grund ist zumindestens, dass $ar, ${arg[1]} und ${arg[1]} nicht gequoted (..."$ar"...) sind.


    ...ich verstehe nicht, wie das gequotet funktionieren sollte.
    Es gibt zwei Stellen, an denen man zusätzlich Quoten könnte:


    1. for do Schleife: Das kann imho so bleibe, da echo die Variablen wie gewünscht ausgibt.
    2. sed-Komando: Hier sind doch die Variablen gequotet !!


    Ich würde mich sehr freuen, wenn du mich aufklären könntest :]


    Gruß
    Wicky

  • Zitat

    Original von SHF
    Ich hab's eben nochmal probiert und es geht auch in einer Zeile:

    Code
    sed -i "/^[ tab]*\#/!{/^.*${1}/s/\(.*\)/${2}/}" ${3}

    Laut meinem Buch soll das zwar nicht gehen, aber es klappt doch. Auch dieses HOWTO gibt es auch in einer Zeile an. ... ich denke ich sollte mal in ein neueres Buch investieren.


    ...wow, sehr kurz und sehr knapp. Aber das wichtiste: Es funktioniert !!
    Bei der Kürze werde ich diese Zeile verwenden.


    Ich danke euch beiden vielmals und ich vermute manch anderer wird diese Zeile auch noch verwenden.


    Gruß
    Wicky

  • @Mirko


    die von dir gepostete bash-Funktion hört sich zunächst sehr verlockend an. Ebenfalls hört es sich sehr gut an, nur mit Bash Methoden zu arbeiten.


    Aber ich vermute, dass man noch einiges um die Bash-Funktion rumbasteln muss. Alles Dinge, die sed für einen erledigen.


    Da ich jedoch vor habe, ein mal eine Funktion zu schreiben, die ich dann immer wieder verwenden kann, so könnte sich der Aufwand eventuell lohnen.


    Es stellt sich nur die Frage, welchen Gewinn man erziehlt.


    Performance:
    Ich glaube nicht, dass sich die vorgestellten Lösungen viel nehmen.


    Kompatibilität:
    sed und bash ändern sich beide (kaum). Aber wenn man busy box verwendet, dann ist eventuell nich jeder sed Befehl verfügbar. Da hier aber sed nicht ausgereizt wird, ist dies imho nicht zu befürchten. Allerdings steht man bei dem sed Ansatz vor einem Problem, wenn sed nicht verfügbar ist. Diese Situation dürfte allerdings höchst selten sein.


    Trozdem werde ich auch mal deinen Ansatz verfolgen. Wenn er allerdings verspricht, zu aufwändig zu werden, dann werde ich ihn nicht bis zum bitteren Ende verfolgen.


    Gruß
    Wicky

  • @all


    Ich nutze die Funktion nun ausgiebig.


    Die Skripte werden deutlich übersichtlicher :]


    Allerdings müssen die Zeichen / und " im NewString und OldString geschützt werden.


    Das finde ich suboptimal. Was mir z.Z. dazu einfällt wäre ein Umwandlung der Strings inerhalb der Funktion bevor die Strings an sed übergeben werden.


    Ich werde das noch einbauen und dann die modifizierte Funktion posten.


    Sehr positiv ist übrigens, dass das Suchmuster auch RegularExpressions enthalten darf !!


    cooper
    Mit dieser Feststellung spiele ich dir vermutlich gerade in die Hände.


    Gruß
    Wicky

  • Ich fand Mirkos Aussage doch zu verlockend um damit mal rumzuspielen.


    Was habe ich hinbekommen: File einlesen, suchen von lines die das gesuchte enthalten und ersetzen mit einer Line mit dem übergebenen Wort (wenn ich die Aufgabe richtig verstanden habe ;) ) .


    Was habe ich nicht hinbekommen: Auskommentierte Zeilen nicht anzufassen.


    Normalerweise müsste doch [^#]*$SEARCH* - eine Line die nicht mit # beginnt und $SEARCH enthält bedeuten oder ?


    Steffen - der jetzt weiss das er nicht viel weiss über die bash :D


    Wicky: ersetzen in der Datei habe ich zum testen nicht eingefügt,

    VDR User: 87 - LaScala LC14B - LG/Phillipps 6,4" VGA Display | Asrock H61/U3S3 | G630T | 1x 16GB Mobi Mtron 3035 1x WD 750GB 2,5" |1x L4m DVB-S2 Version 5.4

Jetzt mitmachen!

Sie haben noch kein Benutzerkonto auf unserer Seite? Registrieren Sie sich kostenlos und nehmen Sie an unserer Community teil!