Bash Variable an awk übergeben



  • Hallo, ich hoffe es kann mir hier geholfen werden.

    Habe leider noch nicht viel Erfahrung beim Scripten unter Linux, und komme gerade beim überreichen einer Variable für das Zwischenspeichern der Bytes für die bereits kopierten Ordner nicht weiter, weil ich ein bestimmtes Limit nicht überschreiten will.

    #!/bin/bash
    
    # give user space time
    logger "[OK] Sony Media Player inserted $1"
    echo yellow > /sys/class/leds/system_led/color
    echo blink  > /sys/class/leds/system_led/blink
    sleep 10
    
    # begin deleting and transfer
    echo red > /sys/class/leds/system_led/color
    echo off > /sys/class/leds/system_led/blink
    
    # mount storage to /mnt/usb
    mount $1 /mnt/usb/
    
    # change user for securti reason
    
    # delete all curent files from storage
    rm -rf /mnt/usb/MUSIC/*
    
    # extract archives files in current folder
    for f in /data/shares/user/*.{zip,rar}
    do
    	SIZE=$(du -sm $f | awk '{ print $1 }')
    	if [ $SIZE > 0 ]
    	then
    		logger "extracting $f ..."
    		echo $f | awk -F "." '
    		{
    			if ($2 == "zip") {
    				system( sprintf( "unzip %s -d %s", $f, $1))
    			}
    			else {
    				system( sprintf( "unrar -o+ e %s %s/", $f, $1))
    			}
    		}'
    		# rm $f 
    	fi
    done
    
    # transfer the folders to storage for max file size ??
    SIZE=0
    
    mkdir /data/shares/user/backup/
    
    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
    
    logger "[INFO] Transfered $SIZE MB to Device"
    
    # work done
    logger "[INFO] unmounting $1..."
    umount $1
    
    logger "[INFO] Files transfer to Sony Walkman done"
    echo green > /sys/class/leds/system_led/color
    echo off  > /sys/class/leds/system_led/blink
    

    Wäre dankbar über Hilfe und evtl. gibts ja bessere Möglichkeiten 👍


  • Mod

    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?



  • 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