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
-
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?!
-
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.
-
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"
-
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.
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.
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.