Anzeige:
Ergebnis 1 bis 10 von 10

Thema: awk - Problem

  1. #1
    Registrierter Benutzer
    Registriert seit
    15.04.2008
    Beiträge
    5

    awk - Problem

    Hallo,
    ich müsste aus Dateien einige Strings ausschneiden, scheitere aber am "awk".

    Ich habe Dateien mit X-Zeilen (immer unterschiedlich) die so aufgebaut sind:

    Item1=ABC_1_3_ah
    Item2=ABD_4_4_hk
    Item3=ABH_t_z_33
    .
    .
    Item380=XBK_5_6_tt


    Aus dem letzten "Item" in dieser Datei soll die Zahl ausgeschnitten werden, in diesem Beispiel also die reine "380".

    Außerdem müsste ich die ItemX-Zeilen ausschneiden das ich dieses Ergebnis bekäme, müsste also "Item*=" weggeschnitten und die _ mit einem Leerschritt ersetzt werden:

    ABC 1 3 ah
    ABD 4 4 hk
    ABH t z 33
    .
    .
    XBK 5 6 tt


    Den "_" sollte ich ja mit | tr "_" " " wegbekommen, aber vom Rest habe ich keine Ahnung.
    Kann mir jemand erklären wie ich das hinbekommen könnte?

    Vielen Dank.

    Gruß,
    Markus

  2. #2
    Registrierter Benutzer Avatar von Detrius
    Registriert seit
    09.03.2004
    Ort
    Altena
    Beiträge
    64
    Code:
    grep Item foo.txt | tail -n 1 | sed 's/Item[0-9]*=//'
    Dann brauchst Du nur noch die Unterstriche ersetzen und das hast Du ja schon.

  3. #3
    Registrierter Benutzer
    Registriert seit
    15.04.2008
    Beiträge
    5
    Danke für deine Antwort.

    Geht noch nicht ganz.

    Mein letzter Eintrag im file.ini lautet: Item385=0

    Script:
    grep -i item file.ini | tail -n 1 | sed 's/Item[0-9]*=//'
    Resultat:
    0

    Ich bräuchte aber die 385!

    Script:
    grep -i item file.ini | tail -n 1 | sed 's/Item//'
    Resultat:
    385=0

    Wie kann ich jetzt aber das "=" Zeichen und was dahinter kommt noch abschneiden ?

    Gruß,
    Markus

  4. #4
    Registrierter Benutzer Avatar von Detrius
    Registriert seit
    09.03.2004
    Ort
    Altena
    Beiträge
    64
    Du willst nur die Nummer haben? Dann
    Code:
    grep Item foo.txt | tail -n 1 | sed 's/Item//' | sed 's/=.*//'

  5. #5
    Registrierter Benutzer
    Registriert seit
    15.04.2008
    Beiträge
    5
    PERFEKT ... funktioniert wunderbar ... DANKE DIR

  6. #6
    Registrierter Benutzer
    Registriert seit
    15.04.2008
    Beiträge
    5
    Einen hätte ich noch:

    ZAHL1=`grep -i item file.ini | tail -n 1 | sed 's/Item//' | sed 's/=.*//'`
    ZAHL2=`expr $ZAHL1 + 1`
    echo "$ZAHL2"

    awk 'NR<=$ZAHL2 {print $0}' file.ini

    Im letzten awk setzte er die Zahl aus der Variable $ZAHL2 nicht um, die wird komplett ignoriert und die komplette Datei ausgegeben, muss ich die anders einsetzen?

    Gruß,
    Markus

  7. #7
    Registrierter Benutzer Avatar von BLUESCREEN3D
    Registriert seit
    08.11.2002
    Beiträge
    665
    In ' werden von der Shell keine Variablen ersetzt. Du musst statt ' einfach " nehmen.

  8. #8
    Registrierter Benutzer
    Registriert seit
    15.04.2008
    Beiträge
    5
    Ohje, sollte vielleicht mal nen SCRIPT-Kurs machen ...:-(

    Klappt wunderbar, DANKE DIR.

    Markus

  9. #9
    Registrierter Benutzer
    Registriert seit
    07.05.2007
    Beiträge
    656
    Moin,

    Zitat Zitat von FireF Beitrag anzeigen
    Einen hätte ich noch:
    ZAHL1=`grep -i item file.ini | tail -n 1 | sed 's/Item//' | sed 's/=.*//'`
    ZAHL2=`expr $ZAHL1 + 1`
    echo "$ZAHL2"
    awk 'NR<=$ZAHL2 {print $0}' file.ini
    da hätte ich auch noch einen ;-)
    Mach dem System das Leben nicht so schwer - da kannst Du einige Prozesse einsparen.

    1. Die beiden sed's kannst Du zusammenlegen:
    Code:
    sed 's/^Item\([0-9]\+\)=.*/\1/'
    Damit wird der Teil zwischen "Item" und dem "=" (gruppiert durch die Klammern) in \1 gespeichert und die ganze matchende Zeile eben durch diesen Puffer ersetzt.

    2. Den grep kannst Du einsparen (die -i-Option ist hier übrigens sinnlos, der sed arbeitet ja auch nicht case-insensitiv):
    Code:
    sed -n '/^Item[0-9]\+=.*/s/^Item\([0-9]\+\)=.*/\1/p'
    Dadurch wird sed stillgelegt (-n Option), schlägt nur an, wenn das Suchmuster zutrifft und schreibt dann explizit raus (/p-Modifier). Den tail kannst Du auch hinten anbammeln:
    Code:
    sed -n '/^Item.\+=.*/s/^Item\([^=]\+\)=.*/\1/p' | tail -1
    3. Der awk ist zum Kürzen von Dateien ein wenig oversized - da gibts einfachere Mittel:
    Code:
    head -n $ZAHL2 file.ini
    So, damit haben wir eine etwas ressourcenschonendere Variante wie folgt:
    Code:
    ZAHL=`sed -n '/^Item[0-9]\+=.*/s/^Item\([0-9]\+\)=.*/\1/p' file.ini | tail -1`
    test -z "$ZAHL" && exit 1
    head -n `expr $ZAHL + 1` file.ini
    Wie Du feststellen wirst, habe ich das Suchmuster etwas angepasst. Das ^ am Anfang stellt sicher, dass "Item" am Anfang der Zeile steht, der reguläre Ausdruck "[0-9]\+" gewährleistet, dass Du tatsächlich eine Zahl in $ZAHL hast. Zum Abfangen eines Fehlers ist die test-Zeile da.

    Jan

    EDIT: Die Ergänzung durch "^" halte ich deshalb für wichtig, weil ja in Ini-Dateien mit ";Item123=..." Einträge im Normalfall auskommentiert werden - die willst Du wahrscheinlich nicht berücksichtigen.

    Nochmal ich: Man muss dem sed natürlich auch eine Datei zum Fraß vorwerfen, hatte ich vergessen.
    Geändert von jan61 (17-04-2008 um 20:05 Uhr)

  10. #10
    Registrierter Benutzer
    Registriert seit
    07.05.2007
    Beiträge
    656
    Moin,

    Zitat Zitat von BLUESCREEN3D Beitrag anzeigen
    In ' werden von der Shell keine Variablen ersetzt. Du musst statt ' einfach " nehmen.
    das ist aber gefährlich - und gibt Probleme:
    Code:
    jan@jack:~/tmp/awk_falle> cat awk_falle.sh
    #! /bin/bash
    export ZAHL=20
    awk " NR<=$ZAHL { print $0 } " file.ini
    jan@jack:~/tmp/awk_falle> ./awk_falle.sh
    awk: Kommandozeile:1:  NR<=20 { print ./awk_falle.sh }
    awk: Kommandozeile:1:                 ^ syntax error
    awk: Kommandozeile:1:  NR<=20 { print ./awk_falle.sh }
    awk: Kommandozeile:1:                   ^ Nicht-beendeter Regulärer Ausdruck
    awk: Kommandozeile:2: (END OF FILE)
    awk: Kommandozeile:2: syntax error
    jan@jack:~/tmp/awk_falle> cat awk_falle_entkommen.sh
    #! /bin/bash
    export ZAHL=20
    awk -v zahl=$ZAHL ' NR<=zahl { print $0 } ' file.ini
    jan@jack:~/tmp/awk_falle> ./awk_falle_entkommen.sh
    Item1=a_b_c
    Item2=33
    Item3=4544
    Item55=A
    letzte Zeile, die geschrieben werden soll
    die Zeile soll nicht mehr auftauchen
    Was ist das Problem? Ganz einfach - $0 ist in jedem Shell-Script der Progammname und wird natürlich durch die fleißige Shell genauso wie $ZAHL ersetzt, bevor der awk überhaupt zum Zug kommt.

    @FireF: Und das funktioniert bei Dir??? *verwirrt guck*

    Besser ist die -v Option des awk, die Shellvariablen an awk-Variablen übergibt.

    Ein anderes Problem habe ich jetzt erst so richtig mitgekriegt (siehst Du oben in der Ausgabe). In meinem vorigen Posting habe ich reine Syntax-Kosmetik betrieben, aber jetzt bin ich auf die semantische Fußnote gestoßen ;-) Du willst einfach nur alle Zeilen bis zum letzten "Item123=..." plus der nächsten Zeile ausgeben, oder irre ich mich da?

    Dann geht Deine Logik natürlich baden, wenn die Item-Zeilen nicht fortlaufend durchnummeriert sind - und nebenbei kann man diese Aufgabe viel einfacher lösen:
    Code:
    ZAHL=`sed -n '/^Item[0-9]\+=.*/=' file.ini | tail -1`
    test -z "$ZAHL" && exit 1
    head -n `expr $ZAHL + 1` file.ini
    Der Modifier "/=" im sed macht die Arbeit - wie vorher wird dem sed ein Nuckel in den Mund gesteckt (-n), damit er nicht losbrüllt und mit dem Modifier wird bei einer passenden Zeile die Zeilennummer (nicht der Inhalt) ausgespuckt. Davon noch die letzte Ausgabe - schon haben wir die letzte passende Zeilennummer. Völlig unabhängig davon, ob da auskommentierte Zeilen sind, Lücken in den Nummern auftauchen usw. Sollte eigentlich (wenn ich Dich nicht völlig falsch verstanden habe) wesentlich betriebssicherer sein.

    Und so sieht es aus:
    Code:
    jan@jack:~/tmp/awk_falle> ZAHL=`sed -n '/^Item[0-9]\+=.*/=' file.ini | tail -1`
    jan@jack:~/tmp/awk_falle> head -n `expr $ZAHL + 1` file.ini
    Item1=a_b_c
    Item2=33
    Item3=4544
    Item55=A
    letzte Zeile, die geschrieben werden soll
    Jan

Lesezeichen

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •