Bash/Kommandozeile - String der durch Leerzeichen getrennt ist zerlegen

  • Hallo Linux-Freunde,

    ich habe folgendes Problem:
    gegeben ist ein String der mehrere Felder besitzt, getrennt durch Leerzeichen. Nun möchte ich ganz einfach das n-te Feld dieses Strings ausgeben lassen. Wie mach ich das am geschicktesten?
    Kann mir kaum vorstellen dass man sich hier selbst einen Parser basteln muss (auch wenns nicht sonderlich viel Arbeit wäre), dieser Mechanismus wird ja auch gebraucht um die Kommandozeilenargumente beim Starten an argv*[] durchzureichen.

    Also ein konkretes Beispiel:

    Code
    $ df -h | grep /dev/md0
    /dev/md0              228G  117G  100G  54% /

    Nun will ich mir von dieser einen Zeile das 5. Feld (also "54%" in dem Fall) ausgeben lassen.

    Hat wer eine Ahnung wie das einfach geht? Ich schätze mal es gibt schon ein Kommando dafür.
    Wenn jemand eine regexp-Lösung hat (sollte ja auch damit leicht gehen), auch fein ;)

    Schöne Grüße,
    fieselschweif

  • Code
    df -h | grep /dev/md0 | awk '{print $5}'


    Man könnte auch cut verwenden (-> Manpage) oder sed mit einer Backlink References. Da weiß ich aber in beiden Fällen die exakte Syntax nicht auswendig.

  • Code
    df -h | grep /dev/md0 | awk '{print $5}'

    Man könnte auch cut verwenden (-> Manpage) oder sed mit einer Backlink References. Da weiß ich aber in beiden Fällen die exakte Syntax nicht auswendig.


    Die Firma dankt :rolleyes:
    Es wär mal interessant sich näher mit sed und awk zu beschäftigen. Kannst du Literatur hierfür empfehlen?

  • Oder man verwendet ein einfaches C-Progamm:

  • Code
    #define FAIL 1


    wie waers mit "EXIT_FAILURE"?

    Code
    } else {
            printf("Error: Couldn't retrieve file system statistics for \"%s\".\n", argv[1]);
        }

    hm, strerror/warn/err/perror/what ever. wenn schon was errno setzt, sollte man das auch nutzen.

    sonst wuerd ich wohl "cut" nehmen.

    Willfähriges Mitglied des Fefe-Zeitbinder-Botnets und der Open Source Tea Party.

  • Die C-Lösung ist auch recht nett, danke dafür!
    Verwenden werde ich sie aber nicht, weil ich ich ja damit (vermutlich) die exakt selbe Berechnung wie df nochmal implementiere und ich generell nichts davon halte das Rad neu zu erfinden, vor allem wenns schon genug Tools gibt die einem die gewünschte Information ausspucken (unter Windows wär das wieder was anderes) und die Performance ja in dem Fall auch völlig egal ist.

    Da ist mir ein schicker Einzeiler mit Pipes lieber :D

  • wie waers mit "EXIT_FAILURE"?

    hm, strerror/warn/err/perror/what ever. wenn schon was errno setzt, sollte man das auch nutzen.


    OMG... Sysprog-Tutor? Also für die Sysprog-Tutoren unter uns:

    vor allem wenns schon genug Tools gibt die einem die gewünschte Information ausspucken


    Es spuckt halt leider nicht jedes Tool die Information in einer leicht nutzbaren Form aus - spätestens, wenn man dann dabei ist, im hundertsten Script die Zeile

    Code
    ADDR=`ifconfig ${IFACE} | grep "inet addr" | sed -e "s/.*inet addr:\([^[:space:]]*\).*/\1/"`


    zu schreiben, kommt man drauf, daß sowas wie

    Code
    ADDR=`ifdata -pa eth1`


    eigentlich doch eleganter ist.

    Außerdem kann es immer sein, daß Sachen auf einmal nicht mehr funktionieren, wenn sich das Ausgabeformat der Tools, aus denen man die Informationen auf die Art rausparst, irgendwann mal ganz minimal ändert.

    Grad bei df kann dir das passieren - "/dev/md0" geht sich ja noch leicht in einer Zeile aus, aber wenn der Pfad der device node lang ist, steht der Pfad in einer Zeile und die dazugehörigen Werte erst in der nächsten:

    Code
    /dev/mapper/server-root
                           90G  7.2G   78G   9% /


    ... und schon funktioniert der Pipeausdruck nicht mehr (und mit sed allein kann man das AFAIK gar nicht reparieren, weils zeilenbasiert arbeitet).

  • OMG... Sysprog-Tutor?


    noe, ich bin nur kein fan dieser selbstgestrickten fehlermeldungen. warum selber was zam schreiben wenn es dafuer wunderbare funktionen gibt? du wirst dir ja auch nicht jedes mal dein eigenes memcpy schreiben. es macht einfach sinn diese funktionen zu verwenden. und wenn es schon EXIT_FAILURE gibt, braucht man auch kein FAIL einfuehren. sysprog-printf ist natuerlich schwachsinn, aber davon hab ich ja nix geschrieben.

    also, no offence, vielleicht hab ich grad meinen kleinlichen tag:engel:

    Willfähriges Mitglied des Fefe-Zeitbinder-Botnets und der Open Source Tea Party.

  • OMG... Sysprog-Tutor? Also für die Sysprog-Tutoren unter uns:

    Code
    #define DODEL_PRINTF(...) if (printf(__VA_ARGS__) < 0) { fprintf(stderr, "Help!\n"); exit(EXIT_FAILURE); }


    das kompiliert aber mit gcc -ansi -pedantic -Wall -g -c *.c nicht ohne warning ;)

    µC-Leitung

  • noch ein Variante

  • noch ein Variante

    Welche Funktion hat die Variable IFS?

  • Jensi:
    Ja es kommt halt drauf an für was ich das Ding konkret brauch - solche Skripts schreib ich meistens nur für mich selbst, und dann weiß ich ganz einfach dass es funktioniert und somit ist die Sache gegessen :rolleyes:
    Falls das für möglichst viele Leute unter möglichst vielen Distributionen und Versionen von Tools funktionieren soll schauts natürlich anders aus, da würd ich u.U. durchaus eine C-Lösung vorziehen falls wirklich die Gefahr besteht dass die Ausgabe sich so großartig unterscheiden kann.

    Aufpassen muss man oft mit Locales, weil man sich dadurch nicht auf gewisse Wörter verlassen darf -

    ADDR=`ifconfig ${IFACE} | grep "inet addr" | sed -e "s/.*inet addr:\([^[:space:]]*\).*/\1/"`


    funktioniert z.B. bei mir nicht, weil es mit deutschen Locales heißt "inet Adresse" statt "inet address" (ein

    Code
    grep "inet "

    würd schon reichen).
    Das ist natürlich auf der einen Seite zusätzliches Argument für C-Lösungen, auf der einen Seite ein Hinweis darauf dass man, WENN man schon Pipe-Lösungen macht wirklich darauf achten sollte dass man sich an Wörtern orientiert die auch sicher immer vorkommen.

    Außerdem kann es immer sein, daß Sachen auf einmal nicht mehr funktionieren, wenn sich das Ausgabeformat der Tools, aus denen man die Informationen auf die Art rausparst, irgendwann mal ganz minimal ändert.

    Grad bei df kann dir das passieren - "/dev/md0" geht sich ja noch leicht in einer Zeile aus, aber wenn der Pfad der device node lang ist, steht der Pfad in einer Zeile und die dazugehörigen Werte erst in der nächsten:

    Code
    /dev/mapper/server-root
                           90G  7.2G   78G   9% /

    ... und schon funktioniert der Pipeausdruck nicht mehr (und mit sed allein kann man das AFAIK gar nicht reparieren, weils zeilenbasiert arbeitet).


    Das Problem lässt sich zum Beispiel noch relativ leicht lösen, hierfür gibts ja POSIX-Standards:

    Code
    df -P

    und schon bist sorgenfrei.
    Ist aber zugegeben auch nicht so leicht herauszufinden, was das genau macht, darüber schweigt sich die Manpage bei mir aus, erst durch info (was ich sonst eigentlich immer vermeide) findet mans raus, oder auch hier: http://www.gnu.org/software/coreu…invocation.html

  • Hab grad zufällig noch was gefunden: mit "stat" kann man auch die Anzahl der Blocks (freie und gesamt) eines Dateisystems anzeigen:

    Code
    stat --file-system --format="%a/%b*100" /my/mount/point | bc -l

Jetzt mitmachen!

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