abfragen ob sed ersetzt hat



  • hallo zusammen,

    ich habe ein skript, mit dem ich eine kleine ersetzung mittels sed durchführe. nun würde ich aber gerne testen, ob sed überhaupt was gemacht hat, also tatsächlich was gefunden hat zum ersetzten. der rückgabewert scheint da keine aussage drüber zu geben. jemand einen tip?

    vielen dank!

    olaf



  • Du kannst den Hashwert/Checksum der Datei vorher und hinterher bestimmen.
    Z.B. mit md5sum



  • Ist awk eine Option?



  • hallo zusammen,

    also mit awk hab ich ehrlich gesagt auch keinen schimmer wie es gehen soll, da komm ich vom regen in die traufe. 😉 however, die eigentliche ersetzung mit sed ist trivial (ersetze XX gegen 10).

    ich muß dies in zwei dateien machen, beim ersten klappt die überprüfung mit md5sum scheinbar, hängt das skript aber auf. hier mal die wesentliche struktur:

    MD5_SUM_BEFORE=$(md5sum ${INPUT_FILE_1})
    sed ...
    MD5_SUM_AFTER=$(md5sum ${INPUT_FILE_1})
    if [[ ${MD5_SUM_BEFORE} == ${MD5_SUM_AFTER} ]]
    then 
      #error case
      # <<<---- hier hängt es :(
    fi
    

    jemand nen tip???



  • Also erst mal perl ist oft eine Lösung, wenn sed oder awk nicht ausreichen. Ein sed, welches einen Fehlercode liefert, wenn nichts ersetzt wurde, sähe in perl eingebettet in ein shell skript etwa so aus:

    if ! perl -pe 'BEGIN {$r=1} $r=0 if s/foo/bar/; END {exit($r)}' <INPUT.txt >OUTPUT.txt
    then
        echo nichts ersetzt
    fi
    

    Sieht ein wenig so aus, als wäre ich auf der Tastatur eingeschlafen und mit dem Kopf auf der Tastatur gelandet, aber so ist halt perl manchmal 😃 .

    Zu Deiner nächsten Frage, warum das Skript hängt, schlage ich vor, mal ein set -x einzubauen, so dass Du siehst, was das Skript eigentlich alles so aufruft. Ein shell Skript kann eigentlich nicht wirklich hängen. Höchstens, wenn es auf eine Eingabe wartet oder eben ein Programm aufgerufen hat, welches hängt.



  • Das geht auch direkt mit sed, falls du GNU sed hast:

    $ echo 'bbaacc' | sed 's/a/x/;x;Ta;s/.*/y/;:a;${s/.//;x;T;q1};x' ; echo $?
    bbxacc
    1
    $ echo 'bbddcc' | sed 's/a/x/;x;Ta;s/.*/y/;:a;${s/.//;x;T;q1};x' ; echo $?
    bbddcc
    0
    

    s/a/x/ ist hier der reguläre Ausdruck. Wenn der mindestens einmal ausgeführt wird, dann ist der exit code 1. Wenn der nie ausgeführt wird, ist der exit code 0.

    Ich hab noch nie ernsthaft sed programmiert, deswegen ist meine Lösung vermutlich unnötig kompliziert.

    Der kommentierte Code ist

    # Regulären Ausdruck anwenden
    s/a/x/
    # Pattern und hold space tauschen, damit wir auf dem hold space arbeiten können.
    x
    # Falls der reguläre Ausdruck vorhin nicht gematcht hat, zu :a branchen.
    Ta
    # Der reguläre Ausdruck hat gematcht. Das wird gespeichert, indem "y" in den hold space gelegt wird.
    s/.*/y/
    # Das anlegen von "y" wird übersprungen, wenn der reguläre Ausdruck gematcht hat, indem direkt zu :a gesprungen wird.
    :a
    # Falls wir in der letzten Zeile sind...
    ${
      # Matcht, wenn der hold space nicht leer ist, also wenn irgendwann mal "y" drin gelandet ist.
      s/.//
      # Pattern space wiederherstellen
      x
      # Falls der hold space leer war, zum Ende des Skripts branchen (führt zu exit code 0).
      T
      # Falls der hold space nicht leer war, hat der ursprüngliche reguläre Ausdruck irgendwann mal gematcht.
      # Also pattern space ausgeben und mit exit code 1 beenden.
      q1
    }
    # Pattern space wiederherstellen. Dadurch landet implizit "y" im hold space, falls bei Ta nicht gesprungen wurde.
    x
    

    edit: Dummen Bug behoben.



  • Ich nehme alles zurück, was ich über die Unlesbarkeit von Perl-Skripten angedeutet habe und behaupte, Perl-Skripte sind gut lesbar 😃 .



  • sed ist eigentlich nicht so schwer, die Syntax ist nur ein bisschen brainf*ck-inspiriert. Das einzige sed-Skript, was ich häufiger nutze, ist

    sed 's/a/b/;s/c/d/;t;d'
    

    Also einen oder mehrere reguläre Ausdrücke und dann ;t;d am Ende. Das sorgt dafür, dass nur die Zeilen ausgegeben werden, in denen mindestes einer der regulären Ausdrücke gematcht hat. Das spart manchmal ein grep.



  • Ich verwende sed auch häufiger. Aber so abgefahrene Sachen, wie Du mache ich dann doch nicht. Wobei sed ein grep auch einfach ersetzen kann:

    sed -n /foo/p
    

    Und auch die berühmten s-Kommandos kann man auch noch unleserlicher gestalten. Beispielsweise verwende ich hin und wieder tatsächlich

    sed ss.......ss
    

    welches die ersten 7 Zeichen jeder Zeile entfernt. Ich mache mir einen Spaß daraus, solche Sachen zu machen, aber ich möchte sie nie jemand anderen zumuten.

    Aber eigentlich ist das t;d auch ganz interessant.

    Wobei ich durchaus empfehlen kann, sich ein wenig in sed und auch awk einzuarbeiten. Die sind halt mächtiger als grep.



  • sed ist sogar turing-vollständig. Nur Arithmetik ist ziemlich hässlich, weil man im ganzen Programm nur zwei String-Variablen hat mit sehr eingeschränkten Operationen.


Anmelden zum Antworten