ubuntuusers.de

shell String to Integer

Status: Ungelöst | Ubuntu-Version: Ubuntu 16.10 (Yakkety Yak)
Antworten |

rs1302

Anmeldungsdatum:
4. Februar 2016

Beiträge: 57

Hallo, ich führe im Terminal einen speedtest-cli aus und filter das Ergebnis, sodaß das Ergebnis nur noch eine Zahl ist. Diese prüfe ich auf Größe um Bedingungen mit if, then..abzurufen.

Auszug aus meinem Skript:

speedtest-cli | awk '/Download:/ {print $2} ' > /root/tmp2;
read speed2 < /root/tmp2
echo $speed2
if [ $speed1 -gt $speed2 ];then
	speed=$speed1;
	sleep 1
	/root/speedchange.sh
fi
echo "MB/s: $speed  , $(date) , $aktfreq " >> /root/speedlog1.log

speed1 wird beim ersten Durchlauf ausgelesen, der Fehler tritt aber erst beim Vergleich "IF Bedingung" mit speed2 auf!

Durch meinen awk Befehl erhalte ich zb "95.56". Dieser Wert wird scheinbar als string bzw nicht als integer gespeichert, da ich bei der If Bedingung einen Fehler bekomme

sh: 95.56: bad number

Mein Skript macht einen speedtest, schaltet dann die LTE Frequenz um und misst nachmals. Je nach Ergebnis, wird auf die erste Frequenz zurück geschalten oder nicht. Alle Teilbereiche funktionieren. Lediglich der Größenvergleich von speed1 und speed2 nicht. Scheinbar werden wie Zahlen nicht als int gespeichert.

Der Umweg über eine Datei war notwendig, da das direkte Zuordnen zu einer Variablen nicht möglich war. zB. das geht nicht

1
speedtest-cli | speed=$(awk '/Download:/ {print $2} ' > /root/tmp2)

Wie kann ich meinen speedtest-cli Befehl "awk-en" um als Ergebnis eine Variable zu erhalten?

frostschutz

Avatar von frostschutz

Anmeldungsdatum:
18. November 2010

Beiträge: 7790

speed=$(speedtest-cli | awk ...)

Wenn du da eine Kommazahl bekommst, das macht die Shell nicht. Da musst du dir was anderes überlegen.

track

Avatar von track

Anmeldungsdatum:
26. Juni 2008

Beiträge: 7174

Wohnort: Wolfen (S-A)

Ja, die Shell kennt zwar keine Typ-Unterscheidung zwischen String und Integer, aber eben auch keine Kommazahlen.

Und eine Kommazahl ist ja nun mal kein Integer, also geht der numerische Vergleich schief.
Aber dafür kennt awk die Funktion int() , oder alternativ auch formatiertes drucken: printf "%.0f\n", $2 .

Übrigens kannst Du Dir die temporäre Datei sparen, und statt dessen eine Command Substiturion nehmen:

speed2=$( speedtest-cli | awk '/Download:/ {print $2}' )

LG,

track

rs1302

(Themenstarter)

Anmeldungsdatum:
4. Februar 2016

Beiträge: 57

Ja, Dezimahlzahlen sind keine Integer! Danke! habe ich nicht bedacht. Dann lösche ich den Punkt und rechne quasi mal 100! das könnte funktionieren und reicht bei einem Vergleich.

Danke für den Hinweis!!!

Command Substitution funktioniert nicht! Genau das hatte ich versucht. Das Skript soll dann auf einem openwrt Router laufen. Dessen shell mag komplexe Befehle nicht. Do,...done oder $(...) Befehle bringen ihn ins schwitzen. Warum habe ich noch nicht herausgefunden, jedenfalls klappts manchmal, 2x später kommt beim gleichen Skript eine Fehlermeldung!

zB:

speed2=$( speedtest-cli | awk '/Download:/ {print $2}' )
sleep 1

führt zu einem Fehler: " 'leep 1 not known....". Scheinbar vergisst er nach komplexen Befehlen das erste Zeichen der nächsten Zeile. Jedoch nicht immer. Bei 4 Durchläufen, bleibt ein Skript rund 1x hängen. Untüpisch für einen Computer, passiert trotzdem... gibt es abgespeckte sh Varianten? Daher muss ich die Befehle einzeln halten und zeilenweise abarbeiten. Der Router ist ein BananaPI. sollte also schnell genug sein.

frostschutz

Avatar von frostschutz

Anmeldungsdatum:
18. November 2010

Beiträge: 7790

Editierst du das mit vi auf der gleichen Kiste? Da passiert mir auch mal daß der Editor Buchstaben verschluckt. 😉

Die busybox-Shell kann das eigentlich, nur mit andern Bashismen muss man da aufpassen.

Kannst du auch bei Ubuntu ausprobieren...

user_unknown

Avatar von user_unknown

Anmeldungsdatum:
10. August 2005

Beiträge: 17620

Wohnort: Berlin

Du solltest nicht den Punkt löschen, sondern

1
awk '{printf "%.02f\n", $2} '

oder

1
awk '{print $2*100} '

benutzen, nicht dass es Dir 27.80 zu 278 abkürzt.

track

Avatar von track

Anmeldungsdatum:
26. Juni 2008

Beiträge: 7174

Wohnort: Wolfen (S-A)

Also, ich würde auch sagen, das Problem muss woanders liegen.
Denn tatsächlich funktioniert es selbst auf der busybox einwanndfrei: (und "kleiner" geht es ja wohl kaum ...)

track@track:~$ busybox sh

BusyBox v1.21.0 (Ubuntu 1:1.21.0-1ubuntu1) built-in shell (ash)
Enter 'help' for a list of built-in commands.

~ $ speed=$(echo "Download: 95.56"  |  awk '/Download:/ {print int($2)}')
~ $ sleep 1
~ $ echo $speed
95 

(wenn Du die Genauigkeit brauchst, kannst Du awk auch gleich multiplizieren lassen ... kostet das gleiche !)

LG,

track

rs1302

(Themenstarter)

Anmeldungsdatum:
4. Februar 2016

Beiträge: 57

@ track: einzeln funktionieren die Befehle auch am Router! in einem Skript direkt hintereinander jedoch nicht! Scheinbar wird das Skript zu schnell abgearbeitet, also die nächste Zeile wird eingelesen, bevor der letzte Befehl fertig ist. Und dabei dürfte es zu Überschneidungen kommen. Werden sh Skripte zuerst in den Speicher gelesen und dann erst gestartet, oder während der Laufzeit, Zeile für Zeile eingelesen? aber egal.... eins nach dem Anderen!

echo 11.40 | sed   's/\.*//g'

Dieser Befehl schneidet den Punkt raus. Die beiden awk Befehle funktionieren nicht!

oot@OpenWrt:~# echo 12.15 |  awk '{printf "%.02f\n", $2} '
0.00

root@OpenWrt:~# echo "12.12" | awk '{print $2*100} '
0

der letzte awk Befehl schaut auch sehr gut aus, damit kann ich beide Prüfungen in einem erledigen! Werde ich gleich mal testen. Genauer brauche ich den Wert tatsächlich nicht! Auf 10er Stellen gerundet wäre auch ausreichend. Sinn des Skripts wird sein, zwei LTE Frequenzen zu vergleichen und letztendlich auf die "bessere" zu schalten. Besser bedeuted in diesem fall "schneller". Aufgrund von normalen Schwankungen macht eine Unterscheidung erst ab 20-30mbit Differenz Sinn.

Mein Skript funktioniert jetzt. Beide versionen. einmal 4stellig mit sed und einmal 2stellig mit awk direkt als Command Substitution übergeben. Ich hoffe es bleibt dabei! ☺ 2stellig mit awk:

speed1=$(speedtest-cli | awk '/Download:/ {print int($2)}')

der awk Einzeiler gefällt mir natürlich bedeutend besser.

4stellig mit sed, "Hilfsdatei" und schrittweise

speedtest-cli | awk '/Download:/ {print $2}' > /root/tmp1; sleep 1
sed  -i 's/\.//g' /root/tmp1
sed -i 's/^ *//;s/ *$//' /root/tmp1
read speed1 < /root/tmp1

Vielen Dank !

frostschutz

Avatar von frostschutz

Anmeldungsdatum:
18. November 2010

Beiträge: 7790

rs1302 schrieb:

Die beiden awk Befehle funktionieren nicht!

oot@OpenWrt:~# echo 12.15 |  awk '{printf "%.02f\n", $2} '
0.00

root@OpenWrt:~# echo "12.12" | awk '{print $2*100} '
0

$2 ist doch weil deine Zeile doch nicht 12.15 heisst sondern Download: 12.15?

rs1302

(Themenstarter)

Anmeldungsdatum:
4. Februar 2016

Beiträge: 57

versteh ich trotzdem nicht danz:

root@OpenWrt:~# speedtest-cli |  awk '{printf "%.02f\n", $2} '
0.00
0.00
0.00
0.00
0.00
0.00
45.80
0.00
36.39
root@OpenWrt:~# speedtest-cli |  awk '/Download:/ {printf "%.02f\n", $2} '
49.03
root@OpenWrt:~# speedtest-cli |  awk '/Download:/ {printf "%.02f\n", $2*100} '
4781.00

was bedeuted "printf "%.02f\n" ? und, wie darf man awk und sed mischen? (nicht nur betreffend dieser Frage)

zB:

echo "Download: 12.11" | ((awk '/Download:/ {print $2}') | sed  's/\.//g')

funktioniert. Ist das so erlaubt und richtig oder gibts einen anderen Weg um $2 gleich zu bearbeiten?

Wei weit darf eine Command Substitution gehen? Rechnen kann man in der Shell doch mit zB:

echo $((100/2))

Warum darf ich meine Zahl dann nicht mehr durch 100 rechnen? Zum Zeitpunkt der Berechnung sollte die zahl doch schon eine Ganzzahl sein!

root@OpenWrt:~# echo "Download: 12.11" | (awk '/Download:/ {printf "%.02f\n", $2*100}' |  sed  's/\.//g')
121100
root@OpenWrt:~# echo "Download: 12.11" | $(((awk '/Download:/ {printf "%.02f\n", $2*100}' |  sed  's/\.//g')/100))
-ash: arithmetic syntax error

PS: das ursprüngliche Problem ist gelöst, wenn ich mich jedoch gerade mit awk und sed beschäftige, schaue ichs mir gleich genauer an! Vielen Dank im Voraus für eure Unterstützung!

rs1302

(Themenstarter)

Anmeldungsdatum:
4. Februar 2016

Beiträge: 57

@track:

ein Beispiel wo Command Substitution bei mir nicht funktionieren will:

root@OpenWrt:~# echo "download 100.000" | awk '/d/ {print $2}'
100.000
root@OpenWrt:~# echo "download 100.000" | temp=$(awk '/d/ {print $2}'); echo $temp

einmal ohne und einmal mit tmp Variable. Über Variable kommt kein Ergebnis.... Kann das jemand erklären?

frostschutz

Avatar von frostschutz

Anmeldungsdatum:
18. November 2010

Beiträge: 7790

Punkt wegmachen ist okay wenn du dir sicher bist daß die Ausgabe schon fest diesem Format entspricht (also immer 2 Nachkommastellen dastehen und nicht nur .8 statt .80).

was bedeuted "printf "%.02f\n" ?

%f steht für Float/Gleitkommazahl und %.2f für mit 2 Nachstellen und %.02f für Nachstellen mit (eigentlich überflüssigen) Nullen.

-ash: arithmetic syntax error

Du hast (befehl) statt $(befehl) geschrieben

Über Variable kommt kein Ergebnis..

Variablenzuweisung innerhalb einer Pipe funktioniert so nicht. Das gilt dann nur für den Subbefehl / in einer Subshell und tangiert die Hauptshell nicht

Ist das gleiche was du im Eingangspost schon versucht hast, siehe dort ...

user_unknown

Avatar von user_unknown

Anmeldungsdatum:
10. August 2005

Beiträge: 17620

Wohnort: Berlin

rs1302 schrieb:

@ track: einzeln funktionieren die Befehle auch am Router! in einem Skript direkt hintereinander jedoch nicht! Scheinbar wird das Skript zu schnell abgearbeitet, also die nächste Zeile wird eingelesen, bevor der letzte Befehl fertig ist. Und dabei dürfte es zu Überschneidungen kommen. Werden sh Skripte zuerst in den Speicher gelesen und dann erst gestartet, oder während der Laufzeit, Zeile für Zeile eingelesen? aber egal.... eins nach dem Anderen!

Wann sie eingelesen werden ist nicht der Punkt. Sie werden strikt zeilenweise abgearbeitet, wenn Du nicht mit dem Ampersand z.B. einen Befehl in den Hintergrund schickst:

1
2
commando1 & 
commando2 

Bei

1
2
commando1 
commando2 

wird commando2 erst gestartet, wenn commando1 fertig ist. Commando1 könnte aber selbst etwas mit Seiteneffekten (sonst macht es keinen Sinn) im Hintergrund starten, und im Vordergrund fertig melden und zurückkehren.

Das printf "%.02f\n" würdest du brauchen, wenn Du den Punkt rausschneiden würdest, damit Du 2 garantierte Nachkommastellen hast, selbst wenn diese 0 sind. Das mit der Multiplikation zu kombinieren ist Quatsch - da brauchst Du es nicht.

Semantisch ist 137.0 eine Ganzzahl, aber syntaktisch ist es eine Fließkommazahl; formal, und darüber beschwert sich die Shell. Die prüft, wo fängt meine Zeihenkette an? 1. Wo hört sie auf? 0. Sind alle Zeichen dazwischn Ziffern? Nein. Also: Arbeitsverweigerung.

1
echo $(( $(echo "Download: 12.11" | awk '/Download:/ {print $2*100}')/10))

Das macht Dir aus 12.10 bis 12.19 jeweils 121 aber aus 12.20 122, so dass Du für kleine Unterschiede an der Überlaufgrenze immer noch einen Unterschied hast, obwohl der Unterschied zw. 12.10 und 12.19 viel größer ist als der zwischen 12.19 und 12.20 - musst Du wissen wie Du das behandelst.

Den Umweg über eine temporäre Datei ersparst Du Dir so:

1
speed1=$(( $(echo "Download: 12.11" | awk '/Download:/ {print $2*100}')/10))

- statt echo download halt speetest-dingens.

bzw.

1
speed1=$(echo "Download: 12.11" | awk '/Download:/ {print int(($2*100)/10)}')

track

Avatar von track

Anmeldungsdatum:
26. Juni 2008

Beiträge: 7174

Wohnort: Wolfen (S-A)

rs1302 schrieb:

ein Beispiel wo Command Substitution bei mir nicht funktionieren will:

root@OpenWrt:~# echo "download 100.000" | awk '/d/ {print $2}'
100.000
root@OpenWrt:~# echo "download 100.000" | temp=$(awk '/d/ {print $2}'); echo $temp

einmal ohne und einmal mit tmp Variable. Über Variable kommt kein Ergebnis.... Kann das jemand erklären?

- äh, ja - die 2. Zeile ... da wirbelst Du wild mit Untershells herum (durch die Pipe !) und wunderst Dich,
dass hinterher bei der Muttershell nix ankommt. Du müsstest Dich da mal zu "Subshells und Environment" einlesen, fürchte ich ...


rs1302 schrieb:

versteh ich trotzdem nicht danz:

root@OpenWrt:~# speedtest-cli |  awk '{printf "%.02f\n", $2} '
0.00
0.00
0.00
0.00
0.00
0.00
45.80
0.00
36.39
root@OpenWrt:~# speedtest-cli |  awk '/Download:/ {printf "%.02f\n", $2} '
49.03
root@OpenWrt:~# speedtest-cli |  awk '/Download:/ {printf "%.02f\n", $2*100} '
4781.00

Wieso ? - hier nimmst Du alle Zeilen (nicht nur die mit dem "Download"), und davon immer das 2. Wort, als Kommazahl.
Ist doch alles korrekt ...? 😉 (Du musst schon sauber arbeiten und genau hingucken, denn awk macht ganz stumpf was Du ihm befiehlst !)

wie darf man awk und sed mischen? (nicht nur betreffend dieser Frage)

Klar darf man, in der Pipe ... nur nötig ist das eigentlich nicht, und meistens auch nicht elegant.

zB:

echo "Download: 12.11" | ((awk '/Download:/ {print $2}') | sed  's/\.//g')

funktioniert. Ist das so erlaubt und richtig oder gibts einen anderen Weg um $2 gleich zu bearbeiten?

Also, erstmal ist das keine Command Substitution oder sowas, sondern Du machst hier 2x ausdrücklich eine Unterhell auf !
→ Lies Dir noch einmal genau durch, was es tatsächlich an Substitutions gibt und was nicht !

Ja, Du kannst awk sagen, es soll mit 100 malnehmen, denn hast Du's auch ...: (haben die Anderen aber auch schon gesagt !)

echo "Download: 12.11" | ((awk '/Download:/ {print $2 * 100}')

Wie weit darf eine Command Substitution gehen?

Beliebig, so viel Du willst.

Rechnen kann man in der Shell doch mit zB:

echo $((100/2))

Ja, nur ist das keine Command Substitution, sondern eine Arithmetic Expansion, also was Anderes !

Warum darf ich meine Zahl dann nicht mehr durch 100 rechnen? Zum Zeitpunkt der Berechnung sollte die zahl doch schon eine Ganzzahl sein!

Klar darfst Du. Du musst nur dran denken, dass die Zahl vorher schon Integer sein muss, und hinterher auf Integer abgeschnitten wird. (also ohne Nachkommastellen !)

root@OpenWrt:~# echo "Download: 12.11" | (awk '/Download:/ {printf "%.02f\n", $2*100}' |  sed  's/\.//g')
121100
root@OpenWrt:~# echo "Download: 12.11" | $(((awk '/Download:/ {printf "%.02f\n", $2*100}' |  sed  's/\.//g')/100))
-ash: arithmetic syntax error

.. nicht genau hingeguckt, wa ? 😉 Du meintest bestimmt sowas:

track@track:~$ echo $(( $( echo "Download: 12.11" | awk '/Download:/ {printf "%.02f\n", $2*100}' |  sed  's/\.//g' )/100 ))
1211 

LG,

track

rs1302

(Themenstarter)

Anmeldungsdatum:
4. Februar 2016

Beiträge: 57

Danke für die Antworten! werde mir das in der Nacht genauer ansehen! lg Roland

Antworten |