So fügen Sie ein Symbol hinzu (oder fügen einfach eine neue Zeile hinzu), wenn die Zahlen im Text nicht fortlaufend sind


7

Ex:

Eingabedatei

A<0>
A<1>
A_D2<2>
A_D2<3>
A<4>
A_D2<6>
A<9>
A_D2<10>
A<13>

Gewünschte Ausgabe:

A<0>
A<1>
A_D2<2>
A_D2<3>
A<4>
-----
A_D2<6>
-----
-----
A<9>
A_D2<10>
-----
-----
A<13>

Achten Sie einfach auf die Nummer in der spitzen Klammer.

Wenn die Zahl nicht fortlaufend ist, fügen Sie ein Symbol hinzu (oder fügen Sie einfach eine neue Zeile hinzu), bis die Zahl wieder fortfährt.

In diesem Fall fehlen die Nummern 5, 7, 8, 11 und 12.

Kann jemand dieses Problem mit dem Befehl awk oder sed (sogar grep) lösen?

Ich bin ein Anfänger in Linux. Bitte erläutern Sie die Details der gesamten Befehlszeile.

Antworten:


11

Die Verwendung grepoder seddafür wird nicht empfohlen, da grepsie nicht zählen kann und sedes wirklich schwierig ist , irgendeine Art von Arithmetik durchzuführen (es müsste eine auf regulären Ausdrücken basierende Zählung sein, ein Nichtstarter für die meisten Menschen außer den dedizierten ).

$ awk -F '[<>]' '{ while ($2 >= ++nr) print "---"; print }' file
A<0>
A<1>
A_D2<2>
A_D2<3>
A<4>
---
A_D2<6>
---
---
A<9>
A_D2<10>
---
---
A<13>

Der awkCode geht davon aus, dass 0dies die erste Nummer sein sollte, und behält dann die gewünschte Zeilennummer für die aktuelle Zeile in der Variablen bei nr. Wenn eine Zahl von der Eingabe gelesen wird, für die eine oder mehrere Zeilen eingefügt werden müssen, erfolgt dies durch die whileSchleife (die auch die nrVariable erhöht ).

Die Zahl in <...>wird durch Angabe dieser Zahl analysiert <und >sollte als Feldtrennzeichen verwendet werden. Die Nummer ist dann in $2(das 2. Feld).


Ah! Sie sehen, das war das Stück, das ich vermisst habe! Verwendung von zwei Feldtrennzeichen.
Markgraf

@markgraf Ich denke, du würdest in Ordnung sein, <obwohl so zB 2>wie 2in einem arithmetischen Kontext bewertet würde .
Kusalananda

4

Dies ist wahrscheinlich alles andere als effizient ...

$ tr '<' '\t' < testfile | tr '>' ' ' \
  | awk '{ while (NR + shift <= $2) { print "-----"; shift++ }; print }' \
  | tr '\t' '<' \
  | tr ' ' '>'
A<0>
A<1>
A_D2<2>
A_D2<3>
A<4>
-----
A_D2<6>
-----
-----
A<9>
A_D2<10>
-----
-----
A<13>

Zuerst verwende ich tr, um zwei durch Tabulatoren getrennte Felder aus der Datei zu erhalten.

Zweitens trersetze ich '>' erneut durch ein Leerzeichen, da sonst mein Befehl awk fehlschlägt: - /

Die Awk-Profis hier werden jetzt wahrscheinlich lachen :-)

Drittens awkvergleicht der Befehl-die Anzahl der verarbeiteten Zeilen mit dem zweiten Feld. Wenn die Anzahl der Zeilen kleiner ist, wird die Markierung gedruckt und erhöht, shiftwas der Anzahl der Zeilen im vorherigen Vergleich hinzugefügt wird.

Viertens und fünftens: Ich mache die Änderungen rückgängig, die ich zuvor vorgenommen habe tr.

Ich habe mich von https://unix.stackexchange.com/a/190707/364705 inspirieren lassen


2
Sie sollten beachten, dass die >Zeichen in den Zeilen 2 bis 4 nicht im Code erscheinen dürfen. Dies ist nur ein zweites Zeichen, das Zeilenfortsetzungen anzeigt.
Shellter

@shellter ist korrekt. Ich habe PS2=\[\033[01;32m\]> \[\e[0m\]in meinem gesetzt .bashrc. Ich werde die Antwort zum leichteren Einfügen bearbeiten.
Markgraf

2

Ich bin kein awkTyp, aber das scheint es auch zu tun. Ich bin immer offen für Verbesserungen:

awk -F '[<>]' -v num=0 '
{
  while(num < $2) {
    print "----";
    num++
  }
  print $1"<"$2">"
  num++
}' file

Zuerst setzen wir das Feldtrennzeichen so, dass es mit den Zeichen <und übereinstimmt >, sodass jede Zeile bei diesen Zeichen aufgeteilt wird. Zum Beispiel würde die erste Zeile zugeordnet werden $1=Aund $2=0.

Dann setzen wir Variable num=0. Wir verwenden es als Zeilenzähler: Wenn die Nummer der aktuellen Zeile $2größer als der Zeilenzähler ist, drucken Sie ----und erhöhen Sie die Zählerwiederholung, bis beide Werte gleich sind. Drucken Sie dann $1<$2>den Zähler aus und erhöhen Sie ihn.


1

So drucken Sie keine gestrichelten Linien vor der ersten Zeile, auch wenn die Zahl in der ersten Zeile nicht Null ist:

$ cat tst.awk
BEGIN { FS="[<>]+" }
{
    curr = $(NF-1)
    if ( NR > 1 ) {
        for (i=prev+1; i<curr; i++) {
            print "-----"
        }
    }
    print
    prev = curr
}

$ awk -f tst.awk file
A<0>
A<1>
A_D2<2>
A_D2<3>
A<4>
-----
A_D2<6>
-----
-----
A<9>
A_D2<10>
-----
-----
A<13>

1

Wir können dieses Problem über reguläre Ausdrücke mit Lookahead und Lookbehind lösen und nur die Bindestriche hinzufügen:

$ perl -0777 -pe 's/^.*<(\d+)>.*\n\K(?=.*<(\d+)>.*$)/qq[-----\n] x ($2-$1-1)/gem' file

Ergebnisse:

A<0>
A<1>
A_D2<2>
A_D2<3>
A<4>
-----
A_D2<6>
-----
-----
A<9>
A_D2<10>
-----
-----
A<13>
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.