HDD-Belegung prüfen und auswerten

Heute ist Stammtischzeit:
Jeden Donnerstag 20:30 Uhr hier im Chat.
Wer Lust hat, kann sich gerne beteiligen. ;)
  • Hallo Ihr Lieben,
    ok erstmal ... was möchte ich machen ...

    Ich möchte einen Pfad auf seinen Inhalt prüfen, heisst wie "voll" dieser ist.

    Code
    usedmem='du -m -s /media/WD-EXT1tb_USB3/Downloads'

    Wenn ich die Variable "usedmem" nun ausgebe steht jetzt in etwa folgendes in der Konsole:

    Zitat

    2815 /media/WD-EXT1tb_USB3/Downloads

    Real scheint aber weiterhin dort drin der oben angegebene Befehl zu stehen.

    Ich benötige aber 100%ig nur die Zahl des benutzten Datenspeichers. (also die 2815 welche sich irgendwann in dem Dreh 500000 bewegen wird ...)
    Jetzt sehe ich zwei Wege dort hin zu kommen ...
    a) die Ausgabe des Befehls von vornherrein beschneiden
    b) dafür sorgen, dass in der Variablen ein String steht, welcher beschnitten und in eine Zahl umgewandelt wird.

    Problem: Ich weiss nicht wie und zahlreiche Suchen haben mich auch nicht weiter, sondern nur zum Verzweifeln gebracht.

    Anwendung:
    Ich möchte den Inhalt einer angeschlossenen und dauerhaft aktiven HDD prüfen und wenn dieser eine bewisse Mindestgröße überschreitet soll eine weitere externe HDD eingeschaltet werden und der Inhalt von der dauerhaft aktiven auf die externe verschoben werden.

    Ich habe hier jetzt schon mehrere Bücher liegen + Sucherei im Netz, ich komm aber an dieser Stelle einfach nicht mehr weiter. :(
    Würde mich über Hilfe freuen,
    herzlichen Dank schonmal, LG Ralf aka synth

    Fotograf, jetzt im Bereich Administration bei AIDA-Cruises tätig

  • Ich hab darüber schon viel gelesen ...
    leider kommt bei mir dann immer das:


    EDIT:
    Gab wohl ne Überschneidung ... hab aber keine weiteren Antworten und den zweiten Code-Teil von dbv nicht mitbekommen.

    Also es funktioniert jetzt ... DANKE!!!

    Eine Frage hätte ich aber noch ...
    wann verwendet man 'befehl', wann "befehl" und wann (befehl)?
    Ich raffs nich ...

    THNX, LG Ralf aka synth

    Fotograf, jetzt im Bereich Administration bei AIDA-Cruises tätig

    Einmal editiert, zuletzt von synth (6. Oktober 2015 um 15:31)

    • Offizieller Beitrag

    Das je nach Anwedungsfall und Programmiersprache anders und steht in der Doku. Für bash gilt

    Code
    BEFEHL #Befehl wird ausgeführt, eventuelle ausgaben sieht man (eventuell) auf der konsole
    var=$(BEFEHL) #Befehl wird ausgeführt, rückgabewerte (augaben) landen anschliessend in der variablen.

    Die ganzen ' "" haben mit Stringmanipulationen zu tun. Das kann besonders absurde und schwer lesbare Konstrukte zur Folge haben. ;)

  • Ich finds besser die Sachen zu erklären und nicht blos fix und fertig vorn Latz zu klatschen. Was lernt er dabei? Nix!


    Also zunächst mal funktioniert beides:

    Code
    var=`du -ms /media/WD-EXT1tb_USB3/Downloads`
    var=$(du -ms /media/WD-EXT1tb_USB3/Downloads)


    Zu beachten ist aber das es nicht ´ oder ' sind sondern `
    Eindeutiger ist dann allerdings die $( ) Schreibweise, welche auch ich bevorzuge.

    Als nächstes gilt das sh oder bash in " nach Variablen sucht, in ' aber nicht weils da auch nicht funktioniert. Bedeutet:
    Funktioniert:

    Code
    echo "$var"


    Funktioniert nicht:

    Code
    echo '$var'

    hier würde er dann nicht den Inhalt der Variable ausgeben sondern schlicht $var
    Was aber auch ginge wäre:

    Code
    echo "'$var'"

    Dann würde der Inhalt der Variable var mit ' umschlossen ausgegeben werden ;)

    Man muss aber auch nicht unbedingt echo "$var" schreiben, die " kann man weg lassen. Auch echo "a b c" muss man nicht machen, auch hier kann man die " weg lassen.

    Das nächste was man wissen sollte ist, das jedes Argument oder Parameter durch ein Leerzeichen getrennt behandelt wird. In einem Script beinhaltet $1 das erste ans Script übergebene Argument, $2 das zweite usw. Das kann man in dem von dbv genannten Beispiel auch direkt übernehmen:

    Code
    echo a b c | awk '{print $1}'

    ist übrigens das selbe wie

    Code
    echo a b c | awk {'print $1'}

    allerdings wäre das erste richtiger :fies:
    ... Es würde also " a " ausgegeben werden weil dass das erste Argument ist. Würde man awk '{print $2}' verwenden würde er "b" ausgeben.

    Das " | " ist eine sog. Pipe. Die Ausgabe des ersten Befehls wird hierbei an den nachfolgenden Befehl übergeben. Wichtig ist das es nur ein einfaches | ist, denn es gibt auch noch das doppelte " || " was aber als ODER betrachtet wird, " && " wäre das Gegenstück: UND

    Man muss auch nicht unbedingt awk verwenden - allerdings ist awk sehr schnell und mächtig.
    Alternativ ginge auch:

    Code
    var=$(du -ms /media/WD-EXT1tb_USB3/Downloads | cut -d'/' -f1)

    -d steht für "delimiter" also Trennzeichen. Ein Leerzeichen geht in diesem Fall nicht, daher nutzen wir einfach eine weitere Möglichkeit: Slash.
    -f bedeutet: Field, also Feld. 1 ist hierbei gleich zu setzen mit: erstes-Argument ( $1 ). -f2 würde dann z.B. "media" ausgeben ;)

    Das man kein Leerzeichen nutzen kann liegt am "du" Befehl. Man könnte aber erst die "du" Ausgabe in die Variable schreiben und anschließend ein cut mit -d' ' darauf anwenden, das ginge wäre aber zu viel geschreibsel und bremst letztlich auch aus (und verbraucht mehr Ram, zwar wenig aber bei größeren Projekten macht sich das bemerkbar)

    Code
    var=$(du -ms /media/WD-EXT1tb_USB3/Downloads)
    var=$(echo $var | cut -d' ' -f1)


    So - another bash basics - done :D

  • Das kommt darauf an wo man das Script verwendet :fies:

    Wenn man es in der Shell verwendet, also nach dem man sich angemeldet hat, sind die Umgebungsvariablen bereits existent und somit auch die Pfade in denen nach den Befehlen gesucht wird. Die Umgebungsvariablen kann man sich mithilfe des Befehls env anzeigen lassen.

    Die Pfade in denen nach Befehlen gesucht wird steht in PATH (Trennzeichen ":") drin, welche in den meisten Fällen vorhanden ist - oder gibst du @ digiart auch auf der Konsole zu jedem Befehl den du ausführst den vollständig Pfad an? :D

    Eine Ausnahme stellen Startup Scripts via /etc/rc.local oder in /etc/init.d/ dar, wo man entweder den absoluten Pfad zu Befehlen angeben sollte, oder vorher selber PATH setzt was auch einige Scripts in /etc/init.d/ machen.

    Eine weitere Ausnahme stellen natürlich die Scripts selbst dar. Solange dies nicht in eine der PATH Verzeichnisse liegt kann es auch nicht ohne absolutem/vollständigem Pfad gefunden werden ;)
    Aber auch hier eine Ausnahme: Das aktuelle Verzeichnis ist " . " das übergeordnete " .. " und wenn man ein Script im aktuellen Verzeichnis ausführen will reicht ein " ./script " - man muss also nicht " /home/pi/script " eingeben, ebenso würde auch " ../script " funktionieren wenn das Script in /home/ läge...

    Aber das sollte an dieser Stelle genug der Grundlagen sein - das ist langsam aber sicher Offtopic!

  • Hi,

    Wollt dazu noch was sagen. (Oder vielleicht auch nur kurz klug.... :lol: )


    ...-d steht für "delimiter" also Trennzeichen. Ein Leerzeichen geht in diesem Fall nicht...

    Du hast ganz vergessen zu sagen wieso ein Leerzeichen in diesem Fall nicht geht.
    An cut liegt es nicht, denn das hat keine Probleme mit einem Leerzeichen als Trenn-/Begrenzungszeichen.

    Der Grund ist einfach dass sich zwischen der Größe und dem Pfad keine Leerzeichen sonder ein Tabulator befindet.
    Aber selbst das ist für cut kein Problem denn der Tabulator wird standardmäßig sogar als delimiter verwendet: ;)

    Zitat


    -d, --delimiter=DELIM
    use DELIM instead of TAB for field delimiter
    man cut

    An die Größe kommt man somit auch so:

    Code
    var=$(du -ms /media/WD-EXT1tb_USB3/Downloads | cut -f1)

    Der "vorteil" von awk ist dass dem egal ist ob das jetzt ein (oder mehrere) Leerzeichen oder ein Tabulator ist denn awk hat standardmäßg beide als Trennzeichen gesetzt.
    Wenn man sich also nicht sicher ist (und es auch nicht sein will bzw. muss) ob das ein Leerzeichen oder ein Tabulator ist, ist awk ganz praktisch. :thumbs1:

    Man kann sich solche "versteckte Zeichen" (Whitespace/Leerraum) aber auch recht einfach anzeigen lassen.
    Ich hab da vor Ewigkeiten cat -A bzw. cat -T für mich entdeckt. Dabei wird der zu untersuchende String einfach an cat "gepipet" welches die Zeichen dann sichtabr macht.

    Sieht dann um beim Beispiel zu bleiben so aus:

    Code
    $ du -ms /media/WD-EXT1tb_USB3/Downloads | cat -T
    23423^I/media/WD-EXT1tb_USB3/Downloads

    Dass das ^I ein Tabulator ist und was der unterschied zwischen -A und -T ist erfährt man in der sehr überschaubaren manpage von cat.

    Code
    man cat


    Joh

    DON'T PANIC!

  • Sorry, ich muss nochmal aufwärmen ...
    habe mittlerweile so weit alles am Laufen, und bekomme auch zwei Tage die Woche jetzt so etwas wie einen Statusbericht.

    Jetzt möchte ich allerdings noch drei Werte (ggf. vier) erhalten, nämlich die, welche df für die gesammte HDD auswürft.
    Problem ... die Spaltenbenennung steht immer mit dabei.

    Aktuell sieht es dann so aus, die Variablen werden beschrieben und in den Text für die Mail eingepflegt ... so beschreibe ich die Variablen:

    Code
    allmem=$(df -m /dev/sda5|awk '{print $2}')
    allusedmem=$(df -m /dev/sda5|awk '{print $3}')
    allavailablemem=$(df -m /dev/sda5|awk '{print $4}')
    allusedpercmem=$(df -m /dev/sda5|awk '{print $5}')


    mit cut hab ich es nicht hinbekomm ... bringt keinerlei Veränderung. :( Ausgabe sieht dann so aus (in der Mail) ...

    Zitat


    1M-Blöcke 953866
    Benutzt 107501
    VerfÃŒgbar 846366
    Verw% 12%

    Danke!

    Fotograf, jetzt im Bereich Administration bei AIDA-Cruises tätig

  • Ich werf dir mal was für die Füße - probier damit mal rum und wenn du in 2 Tagen noch keine Lösung gefunden hast helf ich dir weiter ;)

    Ähnlich aber leicht fehlerhaft:

    Fehlerfrei:


    PS: Guck dir auch mal das an: https://wiki.ubuntuusers.de/Shell/Tipps_und_Tricks

  • Bisheriger Code:

    Hab gerade festgestellt, dass ich aus versehen die .sh mit den Versuchen von Deinem oben geschriebenen überschrieben habe ...
    habe mal rekonstruiert und etwas lauffähigeres hinbekommen, wie bei meinem vorherigen Versuch ... aber funktionierend ist noch etwas anderes ...


    Jetzt bekomme ich folgenden Fehler:

    Zitat

    /home/pi/bin/HDDbericht_test.sh: Zeile 12: read: `Dateisystem 1M-Blöcke Benutzt Verfügbar Verw% Eingehängt auf': Ist kein gültiger Bezeichner.


    Wenn ich es richtig verstehe, habe ich also gerade in der Zeile, welche ich dann nicht haben möchte das Problem. Ich muss allerdings zugeben, dass ich Deinen Code nicht 100%ig verstanden habe ... (wie sich gerade herrausstellt) ... ich habs so verstanden, dass die zwei Zeilen, welche bei "df -m /dev/sda5" ausgegeben werden .. welche da übrigens lauten:

    Zitat

    Dateisystem 1M-Blöcke Benutzt Verfügbar Verw% Eingehängt auf
    /dev/sda5 123456 12345 111111 10% /media/WD-EXT1tb_USB3


    sozusagen der Zeilenumbruch als Marker zum "Trennen der Felder" markiert wird ...

    Fotograf, jetzt im Bereich Administration bei AIDA-Cruises tätig

    Einmal editiert, zuletzt von synth (14. Oktober 2015 um 20:07)

  • Hallo,

    was ist denn das genaue Ziel? Suchst du sowas?

    Code
    df -m /dev/sdxx | awk 'FNR==2 {print "Gesamt:"$2"\nBelegt:"$3"\nVerfuegbar:"$4"\nVerwendet:"$5}'
  • Code
    newallmem=$(df -m /dev/sda5)
    old_IFS=$IFS      # save the field separator          
    IFS=$'\n'     # new field separator, the end of line
    while read -r $newallmem; do
        echo $newallmem
    done < <(df -h)
    IFS=$old_IFS     # restore default field separator

    :s

    Guck dir noch mal meine Vorlage an und vergleiche die Unterschiede zu deinem versuch:

    Du scheinst also allgemein etwas nicht verstanden zu haben. An die while wird am Ende der Input übergeben, in meiner Vorlage geschieht dies über < <(df -h) , das hast du auch so belassen aber stattdessen versuchtest du $newallmem zu verarbeiten - das wird so aber nichts werden.
    Also WENN dann musst du es sorum machen:

    Code
    old_IFS=$IFS      # save the field separator          
    IFS=$'\n'     # new field separator, the end of line
    while read -r line; do
        echo $line
    done < <(df -m /dev/sda5)
    IFS=$old_IFS     # restore default field separator

    Das nächste wäre das du den Header nicht möchtest. Also legst du einen Counter an und sorgst dafür das er für jeden Durchgang der Schleife erhöht wird bzw beim ersten Durchlauf jenen einfach skipped.

    Code
    old_IFS=$IFS      # save the field separator          
    IFS=$'\n'     # new field separator, the end of line
    count=0
    while read -r line; do
        count=$((count+1))
        [ $count = "1" ] && continue
        echo $line
    done < <(df -m /dev/sda5)
    IFS=$old_IFS     # restore default field separator


    @julian92 Lernen ist die Devise, nicht fix und fertig sowie ohne Erklärung vorkauen :no_sad:

  • Danke Dir ... wenn ich das jetzt richtig interpretiere ... wird mit FNR==2 auf die zweite Zeile der Ausgabe verwiesen?

    Umständlich hätte ich also mit

    Code
    df -m /dev/sda5 | awk 'FNR==2 {print $2"\n"$3"\n"$4"\n"$5}'


    alles in eine neue Variable schreiben können um dies dann wieder einzeln zu trennen ... richtig?

    THNX, LG Ralf aka synth


    EDIT: meigrafd
    Genau das war jetzt mein Fehler ... irgendwas hatte ich beim letzten Mal anders, da hatte ich diesen Fehler aber nicht ... werde morgen in Ruhe nochmal Deine Variante ausprobieren ... wie gesagt, mein Versuch von vor x Tagen ist mir abhanden gekommen ... muss das Backup nochmal überarbeiten *feststell* ... allet nich so easy

    Fotograf, jetzt im Bereich Administration bei AIDA-Cruises tätig

    Einmal editiert, zuletzt von synth (14. Oktober 2015 um 21:15)

  • Hallo,
    in Beitrag #10 warst du nahe an der Lösung dran:


    Aktuell sieht es dann so aus, die Variablen werden beschrieben und in den Text für die Mail eingepflegt ... so beschreibe ich die Variablen:

    Code
    allmem=$(df -m /dev/sda5|awk '{print $2}')
    allusedmem=$(df -m /dev/sda5|awk '{print $3}')
    allavailablemem=$(df -m /dev/sda5|awk '{print $4}')
    allusedpercmem=$(df -m /dev/sda5|awk '{print $5}')


    Um an die einzelnen Werte zu kommen, muss awk noch die erste Zeile der Ausgabe entfernen.

    Zitat von synth

    ... wenn ich das jetzt richtig interpretiere ... wird mit FNR==2 auf die zweite Zeile der Ausgabe verwiesen?


    Genau. Angewendet auf deine Befehle aus #10:

    Code
    allmem=$(df -m /dev/sda5 | awk 'FNR==2 {print $2}')
    allusedmem=$(df -m /dev/sda5 | awk 'FNR==2 {print $3}')
    allavailablemem=$(df -m /dev/sda5 | awk 'FNR==2 {print $4}')
    allusedpercmem=$(df -m /dev/sda5 | awk 'FNR==2 {print $5}')
    
    
    echo "$allmem $allusedmem $allavailablemem $allusedpercmem"
  • THNX Ihr Lieben,
    schade, dass ich meinen Ursprünglichen Versuch von meigrafd seiner Version aus Versehen/unfreiwillig gelöscht hab ... hätte jetzt gerne gesehen, wo ich den Fehler hatte, jetzt wo ich beide Wege verstanden habe ...

    Danke Euch Beiden!

    LG Ralf aka synth

    Fotograf, jetzt im Bereich Administration bei AIDA-Cruises tätig

Jetzt mitmachen!

Du hast noch kein Benutzerkonto auf unserer Seite? Registriere dich kostenlos und nimm an unserer Community teil!