[gelöst] Verständnisproblem bei Beispielcounter

Vom einfachen Programm zum fertigen Debian-Paket, Fragen rund um Programmiersprachen, Scripting und Lizenzierung.
Antworten
Benutzeravatar
L3xiE
Beiträge: 7
Registriert: 07.10.2012 21:44:31
Wohnort: Berlin

[gelöst] Verständnisproblem bei Beispielcounter

Beitrag von L3xiE » 07.10.2012 22:19:46

Hi liebe Scipting-Gurus.

Ich habe eine Frage bezüglich der prinzipiellen Funktionsweise eines Counters. Ich versuche dieses Beispiel nachzuvollziehen, habe aber leider arge Schwierigkeiten, da ich in Sachen Shellprogrammierung noch ziemlich unerfahren bin.

Das Skript dient der Beschreibung der Dauer von Niederschlagsereignissen. Wird ein bestimmter Schwellwert in mm überschritten, so liegt ein Ereignis vor, anderenfalls nicht.

Code: Alles auswählen


# Schritt 2 - Funktion
Reihe(){
    SCHWELLE=${1:-0.5}
    INPDATA="\Verzeichnis"
    # NaN umwandeln in -999
    sed -e 's=NaN=-999='  ${INPDATA} | \
	awk "{ if ( \$6 > ${SCHWELLE} ) { print 1 } else { print 0 } }"
}

Counter(){
# Auswertung der Reihe
    WERT=-1
#    for VAL in $(Reihe 0.5)
    for VAL in $*
    do
	if [ ${WERT} -lt 0 ]
	then
	# Initialisierung
	    WERT=${VAL}
	    COUNT=1
	fi
	if [ ${WERT} -eq ${VAL} ]
	then
	# zaehlen
	    COUNT=$((COUNT+1))
	else
	# ausgabe und initialisierung der naechsten zaehlung
	    echo ${WERT} ${COUNT}
	    WERT=${VAL}
	    COUNT=1
	fi
    done
# ausgabe der letzten zaehlung
    echo ${WERT} ${COUNT}
}

Für den Counter benötigen wir wohl die ausgegeben Nullen und Einsen, die jeweils beschreiben, ob ein Schwellwert überschritten wurde oder nicht.
Ich habe nun folgende Fragen:

Warum wird der Wert -1 verwendet?
for VAL in $* ---> Die einzelnen Argumente (also die gewonnenen Nullen und Einsen) werden vor jedem Schleifendurchlauf jeweils nacheinander in die Variable VAL gelegt.

Durch was oder wie verändert sich mein Variable Wert durch die eingelesenen Nullen und Einsen. Ich kann die prinzipielle Funktionsweise irgendwie nicht nachvollziehen. Mein $Wert muss sich ja irgendwie verändern, damit mein Counter zählt.

Ich würde mich riesig freuen, wenn mir jemand bei meinem Verständnisproblem helfen könnte. :)
Zuletzt geändert von L3xiE am 08.10.2012 17:19:36, insgesamt 1-mal geändert.

Benutzeravatar
Dogge
Beiträge: 1899
Registriert: 13.09.2010 11:07:33
Lizenz eigener Beiträge: MIT Lizenz

Re: Verständnisproblem bei Beispielcounter

Beitrag von Dogge » 07.10.2012 22:57:57

Ich kann selbst nur ein bisschen C und kenn mich mit Shell-Scripting gar nicht aus, aber vielleicht findest du dort deine Antworten: http://openbook.galileocomputing.de/she ... ammierung/
Debian Testing + Gnome | Linux-Anfänger seit 04/2003
http://files.mdosch.de/2014-07/0xE13D657D.asc

Benutzeravatar
L3xiE
Beiträge: 7
Registriert: 07.10.2012 21:44:31
Wohnort: Berlin

Re: Verständnisproblem bei Beispielcounter

Beitrag von L3xiE » 07.10.2012 23:05:15

Erstmal danke für den Tipp. :)

Ich verfüge über das Buch, jedoch konnte es mir bei diesem speziellen Problem nicht wirklich weiterhelfen.

Cae
Beiträge: 6349
Registriert: 17.07.2011 23:36:39
Wohnort: 2130706433

Re: Verständnisproblem bei Beispielcounter

Beitrag von Cae » 07.10.2012 23:32:26

Ich habe mir mal erlaubt, die Funktion abzutippen, gescheit zu formatieren, mit Zeilennummern zu versehen und um Kommentare zu bereinigen:

Code: Alles auswählen

  1 counter() {
  2   WERT=-1
  3         
  4   for VAL in $*; do
  5     if [ $WERT -lt 0 ]; then
  6       WERT=$VAL         
  7       COUNT=1           
  8     fi          
  9                 
 10     if [ $WERT -eq $VAL ]; then
 11       COUNT=$((COUNT+1))
 12     else        
 13       echo $WERT $COUNT 
 14       WERT=$VAL         
 15       COUNT=1           
 16     fi          
 17   done  
 18         
 19   echo $WERT $COUNT
 20 }
Erst einmal die Funktion der Funktion:

Code: Alles auswählen

$ counter 1 2 2 2 3 2 4 4
1 2
2 3
3 1
2 1
4 2
Es werden also offensichtlich direkt hintereinanderliegende Dopplungen von Zahlen zu einer Zeile zusammengefasst.

Du fragtest nun, wofür $WERT gut ist. Es hat -1 als Eingangswert (Zeile 2), d.h. im ersten Schleifendurchlauf wird es auf das aktuelle Element gesetzt (5,6). Dabei wird auch der Counter für diesen Wert auf eins gestellt. Anschließend wird überprüft (10), ob das aktuelle Element dem vorhergehenden (welches zuletzt in $WERT gespeichert wurde) gleicht. Falls ja, wird der Counter inkrementiert (11).
Falls nein, haben wir einen neuen Wert, welcher in $WERT gespeichert wird (14), und dessen Counter ist wieder eins (15). Der aktuelle Wert wird mit Häufigkeit ausgegeben (13).

Bei den Testdaten erkennt man auch den Bug in der Funktion: Obwohl der Input 1 2 2 2 ist, wird 1 2, 2 3 ausgegeben. Off-by-one beim ersten Element. Die einfachste Lösung dürfte es sein, den Sonderfall "erstes Element" aus der Schleife rauszunehmen:

Code: Alles auswählen

  1 counter() {
  2   WERT=$1
  3   COUNT=1
  4   shift 
  5 
  6   for VAL in $*; do
  7     if [ $WERT -eq $VAL ]; then
# ...
$ counter 1 2 2 2 3 2 4 4
1 1
2 3
3 1
2 1
4 2
Nun wird das erste übergebene Element direkt in $WERT gespeichert (2), der Counter mit eins initialisiert (3) und mit shift (4) das erste Element in $* weggeworfen. Die Schleife (6) beginnt nun direkt mit der Wiederholungsabfrage (7). Die Testdaten bestätigen das nun korrekte Verhalten.

Reihe() ist übrigens irrelevant für die Funktionsweise, da mit # auskommentiert.

Zur Variablen- und Funktionsbenennung möchte ich dir nahelegen, englische Ausdrücke (zum Beispiel ACT wie active (value) oder actual (value) anstatt WERT) und kleinschreibung mit ggf. Unterstrichen zur Worttrennung. Landessprachliche Bezeichnungen machen internationale Zusammenarbeit schwer, Namen mit KomPliZIERter Schreibweise nerven (mich) einfach (wobei man beim Beispielwort genau wegen der Uneinheitlichkeit l (klein ell) mit I (groß ieh) verwechseln könnte). Puh, das ist jetzt eine Menge zum Scrollen geworden.

Willkommen im Forum!

Gruß Cae
If universal surveillance were the answer, lots of us would have moved to the former East Germany. If surveillance cameras were the answer, camera-happy London, with something like 500,000 of them at a cost of $700 million, would be the safest city on the planet.

—Bruce Schneier

Benutzeravatar
L3xiE
Beiträge: 7
Registriert: 07.10.2012 21:44:31
Wohnort: Berlin

Re: Verständnisproblem bei Beispielcounter

Beitrag von L3xiE » 07.10.2012 23:47:15

Woah,

vielen lieben Dank. :hail:

Mit solch einem Elan und solch einer Hilfsbereitschaft habe ich nun wirklich nicht gerechnet. Ich werde mich morgen vormittag intensiver mit deinem Beitrag auseinandersetzen, jedoch weiß ich jetzt, wie ich in Zukunft meine Programme gestalten werde. Ich werde jedenfalls an meiner Form arbeiten. :mrgreen:

Heute zum ersten mal auf dieses Forum gestoßen und schon von der schieren Kompetenz überwältigt. Sowas erlebt man nicht alle Tage. :THX:

Benutzeravatar
L3xiE
Beiträge: 7
Registriert: 07.10.2012 21:44:31
Wohnort: Berlin

Re: Verständnisproblem bei Beispielcounter

Beitrag von L3xiE » 08.10.2012 15:40:33

Ich habe soweit alles verstanden und mit dem Skript nochmal selber rumgespielt. :)

Der erste Teil des Skripts von Zeile 4 - 8 wird also bloß benötigt, um den Counter erstmal auf 1 zu setzen. Für die darauffolgenden Elemente ($VAL) springt er immer in die nächste if Kontrollstruktur (da die gespeicherten Werte anschließend alle größer als 0 sind) und der Count wird dann bloß noch über (15) auf 1 gesetzt, falls das Element nur einmal vorkommt.

Das einzige was ich jetzt nicht verstehe ist, warum er die -1 als 1 liest? Der Output müsste doch dann folgendermaßen aussehen:

Code: Alles auswählen

-1 1
1 1
2 3
3 1
2 1
4 2
Der InitialWERT ist doch schließlich -1?

Cae
Beiträge: 6349
Registriert: 17.07.2011 23:36:39
Wohnort: 2130706433

Re: Verständnisproblem bei Beispielcounter

Beitrag von Cae » 08.10.2012 17:17:02

Das -1 ist zu Beginn der Schleife in $WERT, ja. Allerdings ist es <0 (5), daher wird $WERT sofort in das erste $VAL geändert (6). -1 taucht also als Wert beim Zähler (10, 11) nie auf.
Wie ich schon geschrieben hatte, tritt dabei aber ein Fehler auf, der erste Wert wird zu Anfang doppelt gezählt. Effektiv passiert da

Code: Alles auswählen

  6 WERT=$VAL   
 10 if [ $WERT -eq $VAL ]; then
 11   COUNT=$((COUNT+1))
D.h. man setzt a gleich b und inkrementiert anschließend, weil a gleich b ist → COUNT ist eins mehr als richtig.

Gruß Cae
If universal surveillance were the answer, lots of us would have moved to the former East Germany. If surveillance cameras were the answer, camera-happy London, with something like 500,000 of them at a cost of $700 million, would be the safest city on the planet.

—Bruce Schneier

Benutzeravatar
r900
Beiträge: 1053
Registriert: 09.10.2011 20:06:11
Lizenz eigener Beiträge: GNU Free Documentation License
Wohnort: Stockholm

Re: Verständnisproblem bei Beispielcounter

Beitrag von r900 » 08.10.2012 17:18:34

L3xiE hat geschrieben:Der InitialWERT ist doch schließlich -1?
Ja, aber der Test in Zeile 5 (lt = less than = kleiner als) ist TRUE und deshalb werden Zeilen 6 und 7 ausgeführt.

Das heißt man kann durch einen Eingabewert von "-1" eine neue Reihe starten. Also VAL= 0 1 1 1 0 1 0 -1 0 1 1 0 1 würde dann dazu führen, dass die Reihen "0 1 1 1 0 1 0" und "0 1 1 0 1" als unabhängige Messreihen behandelt werden. Da die Funktion "Reihe" allerdings nur 0 oder 1 erzeugt, ist diese Formulierung ohnehin unnötig kompliziert.

Benutzeravatar
L3xiE
Beiträge: 7
Registriert: 07.10.2012 21:44:31
Wohnort: Berlin

Re: [gelöst] Verständnisproblem bei Beispielcounter

Beitrag von L3xiE » 08.10.2012 17:20:24

Alles klar.

Danke :THX:

Antworten