Awk: if und bedingte Anweisung im selben Block

Awk: if und bedingte Anweisung im selben Block

Hier ist der Code für ein Skript, in dem ich prüfen muss, ob der Dateiname „pretempsc.cfg“ lautet, und den Inhalt so drucken muss, wie er ist. Nur für alle anderen Dateien muss ich die Zeilen, die mit „abc disable …“ beginnen, in „no abc …“ ändern.

    #!/bin/sh
    IN_FILE=$1
    OUT_FILE=$2

    WhatFileIsIt() {
    awk -v filename=$IN_FILE '
    BEGIN {
        scnode = 0;
        if (filename == "pretempsc.cfg") {
            scnode = 1; }
    }
    {
        if (!scnode) {
            /^abc disable/ {
            print "no abc "$4"";
            next;
            }

            print;}
        }
        else {print}
    }
    '
    }

    cat $IN_FILE | WhatFileIsIt | cat > $OUT_FILE

Beim Ausführen dieses Skripts erhalte ich die folgende Fehlermeldung:

 awk: cmd. line:9:         /^abc disable/ {
 awk: cmd. line:9:                        ^ syntax error
 awk: cmd. line:16:     else {print}
 awk: cmd. line:16:     ^ syntax error

Soweit ich es nachschlagen konnte, vermute ich, dass ich bei der Verwendung von „if“ und „condition-action“ im Aktionsblock einen Fehler mache, kann jedoch nicht genau herausfinden, was falsch ist.

Hinweis: Ich MUSS awk innerhalb des Shell-Skripts verwenden, und es gibt viele andere Funktionen ähnlich zu WhatFileIsIt, die ihre eigene Verarbeitung der IN_FILE durchführen.

Antwort1

Ja, Sie müssen diese Musterübereinstimmung in eine vollständige ifAnweisung ändern:

if (/^abc disable/) {
    print "no abc "$4"";
    next;
}

( /pattern/ist eine Abkürzung für $0 ~ /pattern/, wobei $0die gesamte Eingabezeile enthält.)

Beachten Sie, dass printdort nur die vierte Spalte der Eingabe nach gedruckt wird no abc, sodass abc disable foo bar doonur daraus wird no abc bar. Ich bin nicht sicher, ob Sie das wollten.


Und wenn wir schon dabei sind, fallen mir noch ein paar andere Dinge ein ... Sie können diese ruhig ignorieren, wenn sie zu offensichtlich sind oder mit dem Rest Ihres Skripts in Konflikt stehen. (Und hoffen wir, dass ich nicht zu viele Fehler gemacht habe.)

Ich glaube, am Ende steht eine zusätzliche rechte Klammer print, und die Einrückung der tiefsten Bedingung scheint etwas daneben zu sein, also eine kleine Umschreibung:

{
    if (!scnode) {
        if (/^abc disable/) {
            print "no abc " $4;
            next;
        }
        print;
    } else {
        print;
    }
}

Aber von hier aus scheint es, dass nur dann etwas Besonderes passiert, wenn sowohl !scnodewahr als auch /^abc disable/übereinstimmt, in allen anderen Fällen gibt es nur das print. Wir könnten die Bedingungen also mit kombinieren &&(natürlich ist die Trennung zwischen verschiedenen Dateitypen nicht mehr so ​​klar.):

{
    if (!scnode && /^abc disable/) {
        print "no abc "$4"";
        next;
    } else {
        print;
    }
}

Da es ein gibt next, das die Ausführung abkürzt, printkann das Finale ohne die Klausel stehen else, und da der gesamte Codeblock tatsächlich nur ein ist if, könnten wir die Bedingung auf die Hauptebene fallen lassen und mit einer bedingungslosen Standardaktion des Druckens fortfahren.

!scnode && /^abc disable/ {
    print "no abc "$4"";
    next;
}
1;

(Das sieht jetzt natürlich vielleicht etwas zu komprimiert aus.)


Außerdem müssen Sie die Katzen im Shell-Skript nicht stören. Lassen Sie sie lieber schlafen und verwenden Sie nur die Shell zur Umleitung. (Und setzen Sie die Shell-Variablen in Anführungszeichen.)

 WhatFileIsIt < "$IN_FILE" > "$OUT_FILE"

Der Name dieser Funktion ist etwas verwirrend, sie beantwortet keine wirklichen "Was"-Fragen, sondern verarbeitet eine Datei. Vielleicht so etwas wie ProcessFile?

Und wenn wir schon von Funktionen sprechen: Diese Funktion verwendet die Variable IN_FILE, die nicht lokal ist. Das kann verwirrend sein, wenn eine Funktion jemals für zwei verschiedene Dateien ausgeführt werden muss. Wie das Shell-Skript selbst kann die Funktion auch Parameter annehmen, die aufrufen und innerhalb der Funktion enthalten MyFunction foosein müssen .$1foo

Ich würde also vielleicht so etwas machen wie

ProcessFile() {
awk < "$1" -v filename="$1" '
[...]

(Es spielt keine Rolle, ob Sie die Eingabeumleitung in die Mitte oder am Ende der awk-Befehlszeile einfügen.)

Benutzen mit:

ProcessFile "$IN_FILE" > "$OUT_FILE"

verwandte Informationen