ubuntuusers.de

bash-script: Problem mit variablenübergabe an AWK

Status: Gelöst | Ubuntu-Version: Kubuntu 14.04 (Trusty Tahr)
Antworten |

killercorny

Avatar von killercorny

Anmeldungsdatum:
24. März 2015

Beiträge: 53

Wohnort: Brandenburg

Hallo zusammen!

Ich bin noch relativ neu in der Linux-Materie, auch was bash scripte angeht. Ich habe mir eins zusammengebastelt um die gesamtkapazität der physischen hdds sowie deren freien Speicherplatz anzeigen zu lassen. Das Ganze wird dann ganz zum schluss kompakt als eine zeile ausgeben. Ich nutze hier 2 schleifen jede für sich allein funktioniert, nur nicht zusammen. Und hier kommt ihr ins spiel...

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#/bin/bash
freesize='0000'
#einlesen der physischen hdds -> array
disks=( $(sed -ne 's/.*\([sh]d[a-zA-Z]\+$\)/\1/p' /proc/partitions) )
#alle disks ausgeben:
echo -e "\e[1;37m\033[1m---------------------------------"
for i in ${disks[@]}; do 
  #groesse der hdds auslesen, filtern
  size=$(lsblk | awk -v disklabel=$i '$1==disklabel{print $4}')
  #-------------------------------------------
  echo aktuelle Disk: $i
  echo -----------
  #groesse der partitionen auslesen, ausgabe in MB
  #df --block-size=1M | awk -v disklabel=$i '$1==disklabel{print}'
  echo -----------
  partspace=$(df --block-size=1M | awk -v disklabel=$i '/disklabel/{print $4}')
  for x in ${partspace[@]}; do 
    echo partspace: $x
    #groesse der partitionen addieren
    freesize=`expr "$x" + "$freesize"`
  done
  echo free $freesize" MB"
  echo
  echo
  #-------------------------------------------
  #ausgabe zusammenfassen
  wholestring=$wholestring"\e[1;31m${i} \033[32m${size}iB  ${freesize}MB free  \e[00m"
done

# ausgabe des ergebnisses
echo -e $wholestring
echo -e "\e[1;37m\033[1m---------------------------------"
done

# ausgabe des ergebnisses
echo -e $wholestring
echo -e "\e[1;37m\033[1m---------------------------------"

Das script kann 1:1 kopiert werden, es verwendet keine extra programme, nur die boardmittel. Mein Problem hängt warscheinlich in Zeile 16 an der übergabe der bash-variablen an die variable von awk. Komischer weise funktioniert die selbe syntax in der ersten schleife ab Zeile 7. Zur erklärung: das arry "disks" beinhaltet die bezeichnung der physischen hdds (sda, sdb,...). Zeile 9 für die gesamtkapazität funktioniert auch prima. Zeile 16 soll die ausgabe von df nach den hdd bezeichnungen ($i) filtern und in einem array speichern. Jedoch wird hier nicht richtig gefiltert, bzw. die variable scheinbar nicht korrekt an awk übergeben. Anschließend sollen alle elemente des arrays zusammengezählt werden.

Ich find einfach den Fehler nicht, und meine programmiertkenntnisse sind eher bescheiden.

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13174

killercorny schrieb:

Hallo zusammen!

Herzlich willkommen hier im Forum!

Mein Problem hängt warscheinlich in Zeile 16 an der übergabe der bash-variablen an die variable von awk. Komischer weise funktioniert die selbe syntax in der ersten schleife ab Zeile 7.

Es liegt nicht an der Übergabe sondern an der Verwendung der Variable im awk-Script. In Zeile 16 verwendest Du die Variable nicht im awk-Script. Das am Anfang der Zeile ist ein regulärer Ausdruck, der die Zeichensequenz "disklabel" irgendwo in der Zeile findet. So sollte es gehen (ungetestet):

1
partspace=$(df --block-size=1M | awk -v disklabel=$i '$1==disklabel {print $4}')

Warum nutzt Du nicht einfach df ohne angegebenen Partitionen?

Eine Sache fiel mir noch auf: die Escape-Sequenzen für Farben kannst Du auch mit tput machen - dann sollte es sogar in verschiedenen Terminals gehen.

Ciao

robert

user_unknown

Avatar von user_unknown

Anmeldungsdatum:
10. August 2005

Beiträge: 17604

Wohnort: Berlin

Noch 3 Anmerkungen:

a) Backticks sind deprecated und m.W. auch schlecht portierbar. Schlecht lesbar sind sie auch und man kann sie nicht schachteln. Stattdessen benutz doch $(...), was Du ja auch selbst tust - aber wozu zwei Stile mischen? Das ist schlechter Stil.

b) Arithmetische Operationen mit expr sind auch ungern gesehen. Stattdessen kann man doppelte runde Klammern für arithmetische Ausdrücke verwenden:

1
x=24; freesize=23; freesize=$((x+freesize)); echo $freesize

oder noch kürzer:

1
x=24; freesize=23; ((freesize+=$x)); echo $freesize

c)

1
freesize='0000'

Was soll das sein? Es ist in mehrfacher Hinsicht Humbug, wenn ich nicht einen extremen Hintergedanken übersehe.

Freesize wird als Variable für Ganzzahlen verwendet. Die Schreibung mit einfachen Anführungszeichen deutet an, dass Du die Kette von Nullen vor einer Interpretation maskieren willst wie einen String mit Leerstellen - nur dass keine Leerstelle drin ist. Was soll das - den Leser in die Irre führen, dass es ein String ist?

Als Zahl kann der Wert nur 0 sein. Zahlen mit führender Null werden als Oktal interpretiert, was freilich bei 000 keinen Unterschied macht.

Soll eine Ausgabe von 4 Stellen erzwungen werden? Was soll das?

Das Maskieren von x und freesize später fällt in die gleiche Kategorie. Wenn das Strings sind, die der Maskierung bedüŕfen, dann kracht es an der Stelle eh.

killercorny

(Themenstarter)
Avatar von killercorny

Anmeldungsdatum:
24. März 2015

Beiträge: 53

Wohnort: Brandenburg

Danke schon mal für die Antworten!

killercorny schrieb:

... und meine programmiertkenntnisse sind eher bescheiden.

Das sollte als universelle Antwort reichen.... 😉 Genauer gesagt, hab ich mir das script aus diversen codeschnipseln von foren usw. zusammengebastelt ohne wirklich zu verstehen was das ist. Ich weiß nicht was Escape-Sequenzen, regulärere Ausdrücke, Backticks, etc sind.... Ihr habts hier mit einem absoluten noob zu tun. Von mir aus auch script kiddy, aber dafür bin ich schon reichlich zu alt ^^.

zu

1
freesize='0000'

Das diente ein bisl zum debuggen um am ende zu sehen ob die variable gefüllt wird.

1
((freesize+=$x))

Funktioniert nicht, syntax error im script... ☹

1
freesize=$((x+freesize))

Funktioniert auch nicht, Ergebnis ist Null 😕

rklm schrieb:

killercorny schrieb:

Hallo zusammen!

So sollte es gehen (ungetestet):

1
partspace=$(df --block-size=1M | awk -v disklabel=$i '$1==disklabel {print $4}')

Funktioniert leider nicht, das wäre quasi analog zu Zeile #9 (wo es erstaunlicherweise funktioniert) und hab ich auch schon anfangs versucht. $1== bedeutet glaub, dass das der suchstring am anfang (erste spalte) stehen muss.

Warum nutzt Du nicht einfach df ohne angegebenen Partitionen?

Weil df mir alle partitionen und mount-points ausgibt, ich aber nur die werte von z.b. sda1, sda2, usw zusammenrechnen will. im nächsten schleifen durchgang ist dann sdb usw dran...

Eine Sache fiel mir noch auf: die Escape-Sequenzen für Farben kannst Du auch mit tput machen - dann sollte es sogar in verschiedenen Terminals gehen.

Noch nie davon gehört... 😉

Ciao

robert

EDIT: Ich bin einen kleinen Schritt weiter gekommen. Es liegt an der filterung durch awk.

#16

1
partspace=$(df --block-size=1M | awk -v disklabel=/dev/$i '$1==disklabel {print $4}')

Ich benötige nach $1==disklabel ein wildcard á la $1==disklabel* ... nur hab ich nichts brauchbares außer irgendwas mit ^[0-9] gefunden, funktioniert aber nicht.

Wenn ich in der console

df --block-size=1M | awk -v disklabel=/dev/sda6 '$1==disklabel{print $4}'

eingebe, also den genauen partitionsnamen, bekomm ich auch ein ergebnis! Per variable will ich aber nur sda übergeben, also ohne zahl dahinter. Ich möchte ja alle partitionen einer platte haben. Also muss nach $1==disklabel irgendwie ein wildcard stehen damit alle zeilen die mit /dev/sda anfangen gefiltert werden....

user_unknown

Avatar von user_unknown

Anmeldungsdatum:
10. August 2005

Beiträge: 17604

Wohnort: Berlin

killercorny schrieb:

1
freesize='0000'

Das diente ein bisl zum debuggen um am ende zu sehen ob die variable gefüllt wird.

1
((freesize+=$x))

Funktioniert nicht, syntax error im script... ☹

1
freesize=$((x+freesize))

Funktioniert auch nicht, Ergebnis ist Null 😕

Dann rufsts Du das Skript wohl falsch auf. Wie startest Du es?

1
sh script.sh

oder so ähnlich?

killercorny

(Themenstarter)
Avatar von killercorny

Anmeldungsdatum:
24. März 2015

Beiträge: 53

Wohnort: Brandenburg

Nope, ganz einfach per

1
./test.sh

Hab das mal in ein seperates testscript gepackt:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
#/bin/bash
freesize=0
partspace=( $( df --block-size=1M | awk '/sda/{ print $4}' ) )
for i in ${partspace[@]}; do 
  echo $freesize + $i =
  #groesse der partitionen addieren
  #freesize=`expr "$i" + "$freesize"`
  ((freesize+ =$x))
  #freesize=$((x+freesize))
  echo $freesize
  echo ....
done
echo $freesize" MB"
echo ---------------

Aufruf:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
corny@mypc: ~/testfolder  sh get_free_space.sh 
get_free_space.sh: 3: get_free_space.sh: Syntax error: "(" unexpected
corny@mypc: ~/testfolder  ./get_free_space.sh 
0 + 82180 =
./get_free_space.sh: Zeile 8: ((: freesize+ =: Syntax Fehler: Operator erwartet. (Fehlerverursachendes Zeichen ist »=«).
0
....
0 + 396 =
./get_free_space.sh: Zeile 8: ((: freesize+ =: Syntax Fehler: Operator erwartet. (Fehlerverursachendes Zeichen ist »=«).
0
....
0 + 258118 =
./get_free_space.sh: Zeile 8: ((: freesize+ =: Syntax Fehler: Operator erwartet. (Fehlerverursachendes Zeichen ist »=«).
0
....
0 MB
---------------

seahawk1986

Anmeldungsdatum:
27. Oktober 2006

Beiträge: 11248

Wohnort: München

freesize+ =

Von einem Leerzeichen zwischen + und = hat doch niemand etwas geschrieben...

killercorny

(Themenstarter)
Avatar von killercorny

Anmeldungsdatum:
24. März 2015

Beiträge: 53

Wohnort: Brandenburg

Mein Fehler...aber es kommt trotzdem auf das selbe raus:

1
./get_free_space.sh: Zeile 8: ((: freesize+=: Syntax Fehler: Operator erwartet. (Fehlerverursachendes Zeichen ist »+=«)

seahawk1986

Anmeldungsdatum:
27. Oktober 2006

Beiträge: 11248

Wohnort: München

Du willst vermutlich i dazu addieren und nicht die vorher nicht definierte Variable x.

killercorny

(Themenstarter)
Avatar von killercorny

Anmeldungsdatum:
24. März 2015

Beiträge: 53

Wohnort: Brandenburg

Oh gott bin ich doof... 😳 😲 Man sollte halt nich blind copy&paste betreiben...

Also jetzt gehts auch mit deiner Variante. Kaum macht man's richtig, schon funktionierts.... ^^

Bleibt nur noch mein Problem mit der awk-filterung...

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13174

Nur mal so:

1
partspace=$(df --block-size=1M | awk "/^${i//\//\\/}/ {print \$4}")

killercorny

(Themenstarter)
Avatar von killercorny

Anmeldungsdatum:
24. März 2015

Beiträge: 53

Wohnort: Brandenburg

Hab rausgefunden, das man den Punkt als wildcard verwenden kann. Und ich erhalte auch die Ausgabe die ich haben möchte!

Nur ist wieder das Problem, dass es mit der variablen nicht funktioniert. Ich schätze sie wird nicht als solche erkannt... Die Ausgabe ist dann leer. ☹

Console:

1
2
3
4
5
corny@mypc: ~/testfolder  df --block-size=1M | awk -v disklabel=sda '/.disklabel./{print}'
corny@mypc: ~/testfolder  df --block-size=1M | awk '/.sda./{print}'
/dev/sda5                    96001    8922     82180   10% /
/dev/sda6                      472      52       396   12% /boot
/dev/sda7                   365113   88426    258118   26% /home

seahawk1986

Anmeldungsdatum:
27. Oktober 2006

Beiträge: 11248

Wohnort: München

Mal eine andere Idee:

1
2
3
4
5
6
7
8
9
#!/bin/bash
device="/dev/sda"
partspace=$(df --local --block-size=1M --output=avail,source ${device}?* | grep -oP "(\d+(?=\s${device}\d+))")
for i in ${partspace[@]}; do
    echo -n "$freesize + $i = "
    ((freesize+=$i))
    echo "$freesize"
    echo ....
done

killercorny

(Themenstarter)
Avatar von killercorny

Anmeldungsdatum:
24. März 2015

Beiträge: 53

Wohnort: Brandenburg

Halleluja!

DAS ist die Lösung die ich brauchte! Vielen Dank! Jetzt muss ich nur noch alles zusammen basteln und dann ist es fertig...

track

Avatar von track

Anmeldungsdatum:
26. Juni 2008

Beiträge: 7174

Wohnort: Wolfen (S-A)

Fehlt da in Zeile 3 nicht das Klammerpaar für das Array ?

... und die Zeilen 5-7 kann man wunderschön zusammenfassen zu einer:

1
echo "$freesize + $i = $((freesize+=i))"

LG,

track

Antworten |