Bash Variable an awk übergeben



  • SeppJ schrieb:

    Kannst du genauer sagen, was dein Problem ist? Ein langes Programm und die Aussage, dass du nicht weiter kämst, ist nicht sehr hilfreich.

    Was willst du erreichen? Was hast du versucht? Was erwartest du? Was passiert stattdessen?

    Das Weiterverarbeiten von Ausgaben von ls ist fast immer falsch in Shellscripten. Was genau soll da erreicht werden?

    Ja hast recht, hab vergessen dazu zuschreiben, dass die SIZE größe immer
    den Wert 0 hat, ich weiß das ich sie zwar übergebe, aber den Wert den ich ihr dann zuweise, geht natürlich wieder verloren, weil ich den Wert den ich in awk setze nicht zurückgebe. Und das ist das Problem, somit kann ich nie prüfen ob bereits wie im Beispiel 6000 MB kopiert wurden.

    Ich möchte nur wissen, ob es da eine effizientere Möglichkeit gibt, oder muss ich das die Ausgabe von awk irgendwie per echo an SIZE zurückgeben?!


  • Mod

    Du willst also nicht von der bash etwas an awk übergeben, sondern von awk aus den Wert im Script verändern? Letztlich kann man aus einem Kindprozess keine Variablen im Elternprozess ändern. So etwas wie in Zeile 25 muss also reichen. Ich sehe aber nicht, dass bei deinem komplexeren Kommando etwas gegen diese Methode spräche.



  • SeppJ schrieb:

    Du willst also nicht von der bash etwas an awk übergeben, sondern von awk aus den Wert im Script verändern? Letztlich kann man aus einem Kindprozess keine Variablen im Elternprozess ändern. So etwas wie in Zeile 25 muss also reichen. Ich sehe aber nicht, dass bei deinem komplexeren Kommando etwas gegen diese Methode spräche.

    Genau so wie in der Zeile 25, möchte ich nun das auf Ordner anwenden und nicht
    auf gepackte Datein, weil der Speicherplatz nach dem entpacken ein anderer ist.

    Deswegen möchte ich alle vorhandene Ordner auf das Device kopieren, aber auf eine bestimmte Größe wie 6000 mb limitieren.

    ls -l /data/shares/user/ | grep '^d' | awk -v s=$SIZE' {
        cmd = "du -sm /data/shares/peter/" $9;
        cmd |getline $1;
        split($1, output_arr, " ");
        s += output_arr[1];
        close(cmd);
        printf("File: %s - Size: %s\n", $9, output_arr[1]);
        if (s < 6000 && "$9" != "backup") {
            system( sprintf("logger \"copying /data/shares/peter/%s to device...\"", $9));
            system( sprintf("cp -r /data/shares/peter/%s /mnt/usb/MUSIC/%s", $9, $9));
            system( sprintf("mv /data/shares/peter/%s /data/shares/peter/backup/%s", $9, $9));
        }
        print s;
    }' < SIZE
    

    Hintergrund vom ganzen Script ist, das ich per udev rule ein USB Datenträger erkennen will, und wenn das zutrifft soll er das Script abarbeiten.


  • Mod

    Und wieso machst du es dann nicht so wie in Zeile 25?

    PS: rsync kennst du? Es wirkt ein bisschen so, als würdest du es gerade nachprogrammieren...



  • Super vielen Dank für den Hinweis,

    hätte nicht gedacht das man auch durch Ordner iterieren kann. Aber es geht ! 😃

    hier die Lösung:

    #!/bin/bash
    
    SIZE=0
    
    for dir in /data/shares/user/*/
    do
            CURRENT_DIR="$(basename "${dir}")"
            DIR_SIZE=$(du -sm $dir | awk '{ print $1 }')
            if [ "$((SIZE+DIR_SIZE))" -lt "6000" ]
            then
                    SIZE=$((SIZE+DIR_SIZE))
                    logger "copying ${CURRENT_DIR} ($DIR_SIZE MB) to device..."
                    system( sprintf("cp -r /data/shares/user/%s /mnt/usb/MUSIC/%s", ${CURRENT_DIR}, ${CURRENT_DIR) );
                    system( sprintf("mv /data/shares/user/%s /data/shares/user/backup/%s", ${CURRENT_DIR}, ${CURRENT_DIR) );
    
            fi
    done
    logger "[INFO] Transferd total $SIZE MB to device"
    

  • Mod

    Das sieht doch schon gleich viel besser aus 👍 .

    awk '{ print $1 }'
    

    Bei dieser Art von Benutzung auch besser bekannt als cut 😉

    Hat es eigentlich einen tieferen Grund, warum du ein Kommando mit sprintf zusammen setzt und dann mit system ausführst, anstatt es, nun ja, einfach auszuführen? So a la

    cp -r /data/shares/user/${CURRENT_DIR} /mnt/usb/MUSIC/${CURRENT_DIR}
    

    oder, da cp nicht doof ist:

    cp -r /data/shares/user/${CURRENT_DIR} /mnt/usb/MUSIC/
    


  • SeppJ schrieb:

    Das sieht doch schon gleich viel besser aus 👍 .

    awk '{ print $1 }'
    

    Bei dieser Art von Benutzung auch besser bekannt als cut 😉

    Hat es eigentlich einen tieferen Grund, warum du ein Kommando mit sprintf zusammen setzt und dann mit system ausführst, anstatt es, nun ja, einfach auszuführen? So a la

    cp -r /data/shares/user/${CURRENT_DIR} /mnt/usb/MUSIC/${CURRENT_DIR}
    

    oder, da cp nicht doof ist:

    cp -r /data/shares/user/${CURRENT_DIR} /mnt/usb/MUSIC/
    

    cat würde mir doch die Größe und den Namen zurückgeben, mit print $1 gebe ich nur die Größe zurück, den Namen brauche ich ja nicht.

    Und nein hat keinen tieferen Grund 😃 , copy & paste aus der vorherigen awk Programmierung, kann man hier natürlich weglassen.

    Nochmals Danke



  • DKlay schrieb:

    cat würde mir doch die Größe und den Namen zurückgeben, mit print $1 gebe ich nur die Größe zurück, den Namen brauche ich ja nicht.

    man: cut, nicht man: cat. 🙂

    du -sm $dir | cut -f 1
    


  • nman schrieb:

    DKlay schrieb:

    cat würde mir doch die Größe und den Namen zurückgeben, mit print $1 gebe ich nur die Größe zurück, den Namen brauche ich ja nicht.

    man: cut, nicht man: cat. 🙂

    du -sm $dir | cut -f 1
    

    hmm und welche Vorteile ergeben sich hiermit?

    $(du -sm $dir | awk '{ print $1 }') vs du -sm $dir | cut -f 1

    weniger mögliche Syntax fehler? 😃



  • cut ist viel simpler. Kein Grund die großen Eisen (awk) auszupacken, wenn du es mit den kleinen (cut) auch erledigen kannst.

    Never use awk when you can use sed.
    Never use sed when you can use grep.
    Never use grep when you can use cut.

    Oder so ähnlich. 🙂


Anmelden zum Antworten