ubuntuusers.de

Nicht-Integer-while-Bedingungen

Status: Gelöst | Ubuntu-Version: Xubuntu 16.04 (Xenial Xerus)
Antworten |

KeyzerSoze

Anmeldungsdatum:
28. September 2014

Beiträge: 120

Hallo ubuntuusers,

ich würde gerne eine while-Schleife mit folgender Bedingung ausführen: (wenn alle Nicht-Integer durch Integer ersetzt werden, dann sollte der Code funktionieren)

i=3.2
while (( $i<=5.2 )); do
./startskript1.sh $i
./startskript2.sh $i
i=$((i + 0.3 ))
done

Das Problem ist bash und NICHT-Integers...

Letztere Rechnung kann ich ja durch perl ersetzen:

i=$(perl -E "say $i+0.3")

Aber bei der while-Schleifenbedingung bin ich ratlos.

Oder wäre es angebracht/empfehlenswert perl ganz weg zu lassen und awk zu verwenden? Aber kann die awk-Umbebung auch Bashskripte aufrufen und ausführen?

Ich wäre auch für eine der while-Schleife äquivalente for-Schleife aufgeschlossen ☺

Viele Grüße und vielen Dank im Voraus!

Prof._Frink

Anmeldungsdatum:
29. Mai 2010

Beiträge: Zähle...

Hey,

multipliziere für das Auswerten der Testbedingung doch mit 10

1
2
3
4
5
6
i=32
while [[ $i -le 52 ]]; do
    ./startskript1.sh $(echo $i/10. | bc -l )
    ./startskript2.sh $(echo $i/10. | bc -l )
    i=$((i + 3 ))
done

Viele Grüße,

Frink

Prof._Frink

Anmeldungsdatum:
29. Mai 2010

Beiträge: Zähle...

Oder benutze seq

1
2
3
4
for i in $(seq 3.2 0.3 5.2); do
    ./startskript1.sh $i
    ./startskript2.sh $i
done

KeyzerSoze

(Themenstarter)

Anmeldungsdatum:
28. September 2014

Beiträge: 120

Hallo Frink, danke für deine Antwort ☺

Prof._Frink schrieb:

Hey,

multipliziere für das Auswerten der Testbedingung doch mit 10

Daran habe ich auch schon gedacht, für dieses einfache Beispiel ist das gut praktikabel, für "den Alltag", wo sich diese Variablen ständig verändern (in der Anzahl der Nachkommastellen), finde ich es aber zu aufwendig und evtl. fehleranfällig. Ich würde eine saubere Lösung bevorzugen, anstelle eines workarounds ☺

Edit: Dein zweiter Beitrag klingt aber sehr gut ☺ Prof._Frink schrieb:

Oder benutze seq

user_unknown

Avatar von user_unknown

Anmeldungsdatum:
10. August 2005

Beiträge: 17674

Wohnort: Berlin

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
i=32
while (( $i <= 52 )); do echo ${i:0:1}.${i:1:1}; i=$((i+3)); done ; echo $i 
3.2
3.5
3.8
4.1
4.4
4.7
5.0
53

Ah, da waren einige schneller. ☺ Tabparking. ☺

track

Avatar von track

Anmeldungsdatum:
26. Juni 2008

Beiträge: 7174

Wohnort: Wolfen (S-A)

Grundsätzlich funktioniert Shell Arithmetik nur mit Integer-Zahlen.

Sobald also Nachkommastellen, oder sonstwie Fließkomma-Zahlen ins Spiel kommen, brauchst Du was anderes. (egal ob das nun awk, Perl oder bc heißt)

Wenn so ein Skript zahlenlastig ist, lohnt es sich ganz sicher, das Skript gleich komplett als awk- oder Perlskript zu bauen:

1
2
3
4
5
6
#!/usr/bin/awk -f

BEGIN {	for(i=3.2; i<=5.2; i+=0.3)  {
		"./startskript1.sh"  i;
		"./startskript2.sh"  i;  }
	}

Eine Frage ist auch, ob Du jetzt Dezimalpunkte oder -kommas brauchst !

LG,

track

KeyzerSoze

(Themenstarter)

Anmeldungsdatum:
28. September 2014

Beiträge: 120

Danke für Eure Antworten ☺

track schrieb:

Eine Frage ist auch, ob Du jetzt Dezimalpunkte oder -kommas brauchst !

Du meinst wie das

 LC_NUMERIC 

in .bashrc gesetzt ist?

Was mir des Weiteren noch unklar ist, wenn ich in der Shell ein (g)awk-Skript aufrufe mit ./meinskript.awk,

#!/usr/bin/awk -f
...
...

wie ich dann Variablen übergebe: Geht es nur auf diese Art und Weise: ./meinskript.awk -v v1=variable1 -v v2=variable2 ...?

Danke und viele Grüße

schusch

Avatar von schusch

Anmeldungsdatum:
2. September 2008

Beiträge: 324

Wohnort: Berlin

Wenn man bc nimmt, würde ich vorschlagen:

1
2
3
4
$ while [ $(echo "$i"'<=5.2' | bc) -eq 1 ] ; do
...
i=$(echo "$i"+1 | bc)
done

Ich würde hier allerdings auch awk vorziehen.

😎

track

Avatar von track

Anmeldungsdatum:
26. Juni 2008

Beiträge: 7174

Wohnort: Wolfen (S-A)

KeyzerSoze schrieb:

Eine Frage ist auch, ob Du jetzt Dezimalpunkte oder -kommas brauchst !

Du meinst wie das

 LC_NUMERIC 

in .bashrc gesetzt ist?

Nein, in diesem Fall war meine Frage eher, was Deine beiden Skripte erwarten. (ich weiß ja nicht, was da drin ist !)

Was mir des Weiteren noch unklar ist, wenn ich in der Shell ein (g)awk-Skript aufrufe mit ./meinskript.awk

Ja, wenn das Skript im aktuellen Verzeichnis liegt, schon.
Sonst ist der bessere Weg, das Skript in /user/[Login_Name]/bin abzulegen. Dann kannst Du es ganz normal als Befehl aufrufen, direkt mit   meinskript.awk .

wie ich dann Variablen übergebe:

./meinskript.awk -v v1=variable1 -v v2=variable2 ...?

Wird so nicht gehen. (Bedenke bitte: es wird blind die komplette Shebang-Zeile ausgeführt, mit dem Skriptnamen und allen Parametern dahinter !)
Aber gawk kann selber auf das Shell-Environment zugreifen:

1
v1=variable1 v2=variable2  ./meinskript.awk

und im Skript dann:

1
2
3
4
5
6
#!/usr/bin/awk -f

BEGIN	{
	print "in $v1 steht:", ENVIRON["v1"];
	print "in $v2 steht:", ENVIRON["v2"];
	}

Genauso gut könntest Du auch solche Werte direkt als Shell-Parameter an das awk-Skript übergeben: (solange es dort nur BEGIN-Blöcke gibt !)

1
./meinskript.awk  variable1  variable2

und im Skript dann:

1
2
3
4
5
6
#!/usr/bin/awk -f

BEGIN	{
	print "Parameter 1:", ARGV[1];
	print "Parameter 2:", ARGV[2];
	}

LG,

track

D630

Avatar von D630

Anmeldungsdatum:
24. Juli 2013

Beiträge: 329

Wegen der Vollständigkeit: ksh und zsh können mit Floats rechnen (jedoch unterschiedlich). Zum Beispiel:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#!/usr/bin/env ksh

function run_in_ksh {
    [[ -n "$LC_ALL" ]] &&
        typeset lc_all=$LC_ALL LC_ALL=;

    typeset -lE \
        i=$1 \
        j=$2 \
        k=${3? too few arguments};

    typeset LC_ALL=C;

    run_in_ksh_locale () { print $i; };

    for ((; i <= j; i+=k)); do
        LC_ALL=$lc_all run_in_ksh_locale;
    done;
};

# typeset -x LC_ALL=C;
# LANG=de_DE.UTF-8 run_in_ksh 3,2 5,2 0,3
# LANG=de_DE.UTF-8 run_in_ksh 3.2 5.2 0.3
# LANG=en_EN.UTF-8 run_in_ksh 3.2 5.2 0.3

:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/usr/bin/env zsh

function run_in_zsh {
    [[ $@ == "${@//,/}" ]] || {
        printf 'use periods, please\n' 1>&2;
        return 1;
    };

    typeset LC_ALL=C;

    typeset -lE \
        i=$1 \
        j=$2 \
        k=${3? too few arguments};

    for ((; i <= j; i+=k)); do
        printf '%g\n' $i;
    done;
};

# LANG=de_DE.UTF-8 run_in_zsh 3,2 5,2 0,3
# LANG=de_DE.UTF-8 run_in_zsh 3.2 5.2 0.3
# LANG=en_EN.UTF-8 run_in_zsh 3.2 5.2 0.3

D630

Avatar von D630

Anmeldungsdatum:
24. Juli 2013

Beiträge: 329

Die Beispiele mit bc würde ich etwas abändern; bc nur einmal starten:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
#!/bin/sh

run_in_posix () {
    : ${3? too few arguments};

    test "$*" = "${*##*,*}" || {
        printf 'use periods, please\n' 1>&2;
        return 1;
    };

    LC_ALL=C bc <<!
        for (i = ${1:-0}; i <= ${2:-0}; i += ${3:-0}) i;
!
};

export POSIXLY_CORRECT=1
# LANG=de_DE.UTF-8 run_in_posix 3,2 5,2 0,3
# LANG=de_DE.UTF-8 run_in_posix 3.2 5.2 0.3
# LANG=en_EN.UTF-8 run_in_posix 3.2 5.2 0.3;

:

edits: 2

KeyzerSoze

(Themenstarter)

Anmeldungsdatum:
28. September 2014

Beiträge: 120

Okay, meine Frage ist mehr als beantwortet ☺ Vielen Dank Euch allen ☺

Antworten |