Sie können nur zwei Zahlen mit " dcGefällt mir" vergleichen :
dc -e "[$1]sM $2d $1<Mp"
... wo "$1"ist dein Maximalwert und "$2"ist die Zahl, die du drucken würdest, wenn sie kleiner ist als "$1". Das erfordert auch GNU dc- aber Sie können dasselbe portabel machen wie:
dc <<MAX
[$1]sM $2d $1<Mp
MAX
In beiden oben genannten Fällen können Sie die Präzision auf etwas anderes als 0 gesetzt (Standardeinstellung) wie ${desired_precision}k. Für beide ist es auch zwingend notwendig , dass Sie sicherstellen , dass beide Werte sind definitiv Zahlen , weil dckönnen machen system()Anrufe w / der !Betreiber.
Mit dem folgenden kleinen Skript (und dem nächsten) sollten Sie auch die Eingabe überprüfen - wie grep -v \!|dcoder so etwas, um willkürliche Eingaben sicher zu handhaben. Sie sollten auch wissen, dass dcnegative Zahlen _eher mit einem Präfix als mit einem Präfix interpretiert werden, -da letzteres der Subtraktionsoperator ist.
Abgesehen davon dcliest dieses Skript so viele fortlaufende \newline-getrennte Zahlen ein, wie Sie bereitstellen möchten, und druckt für jeden $maxWert oder für jede Eingabe, je nachdem, welche die kleinere der beiden ist:
dc -e "${max}sm
[ z 0=? d lm<M p s0 lTx ]ST
[ ? z 0!=T q ]S?
[ s0 lm ]SM lTx"
So ... jedes dieser [quadratischen klammert ]Weiten ist ein dc String - Objekt , das sich Sjeweils an seinem jeweiligen Array Aved - einem der T, ?, oder M. Neben ein paar anderen Dingen, dcdie mit einer Zeichenfolge zu tun haben , kann sie auch xals Makro ausgeführt werden. Wenn Sie es richtig anordnen, wird ein voll funktionsfähiges kleines dcSkript einfach genug zusammengestellt.
dcarbeitet auf einem Stapel . Alle Eingabeobjekte werden nacheinander gestapelt - jedes neue Eingabeobjekt schiebt das letzte obere Objekt und alle Objekte darunter beim Hinzufügen um eins nach unten auf den Stapel. Die meisten Verweise auf ein Objekt sind auf dem oberen Stapelwert und die meisten Referenzen Pop , dass oben auf dem Stack (die durch eine alle Objekte darunter nach oben zieht) .
Neben dem Hauptstapel gibt es (mindestens) 256 Arrays, und jedes Array-Element verfügt über einen eigenen Stapel. Davon verwende ich hier nicht viel. Ich speichere nur die Saiten wie erwähnt , so kann ich lsie oad wenn wollte und e xsie ecute bedingt, und ich sriss $max‚s - Wert in der Spitze des mArrays.
Wie auch immer, dieses kleine bisschen dcmacht im Großen und Ganzen das, was Ihr Shell-Skript macht. Es verwendet die GNU-ism- -eOption, die im dcAllgemeinen die Standard-In-Parameter verwendet, aber Sie können das Gleiche tun wie:
echo "$script" | cat - /dev/tty | dc
... wenn es $scriptso aussieht.
Es funktioniert wie folgt:
lTx- Dies llädt und xführt das Makro aus, das oben in gespeichert ist T (zum Test, denke ich - ich wähle diese Namen normalerweise willkürlich aus) .
z 0=?- Test testet dann die Stapeltiefe mit zund ruft das Makro auf , wenn der Stapel leer ist (read: enthält 0 Objekte)? .
? z0!=T q- Das ?Makro ist nach dem ? dceingebauten Befehl benannt, der eine Eingabezeile aus stdin liest, aber ich habe ihm auch einen weiteren zStapeltiefen-Test hinzugefügt , damit es qdas ganze kleine Programm beenden kann , wenn es eine leere Zeile einliest oder EOF drückt. Wenn dies jedoch !nicht der Fall ist und der Stapel stattdessen erfolgreich gefüllt wird, wird Test erneut aufgerufen.
d lm<M- Test dkopiert dann den oberen Teil des Stapels und vergleicht ihn mit $max (wie in gespeichert m) . Wenn mder kleinere Wert ist, wird dcdas MMakro aufgerufen.
s0 lm- MKnallt einfach die Oberseite des Stapels und wirft sie auf den Dummy-Skalar. 0- Nur eine billige Art, den Stapel zu knallen. Es wird auch wieder lgeladen m, bevor zu Test zurückgekehrt wird.
p- Dies bedeutet, dass wenn mkleiner als die aktuelle Stapelspitze ist, diese mersetzt wird ( djedenfalls das Uplikat davon) und hier pgedruckt wird, andernfalls wird sie nicht gedruckt, und was auch immer die Eingabe war, wird pstattdessen gedruckt.
s0- Danach (weil pder Stapel nicht aufgeht) legen wir den oberen Teil des Stapels 0wieder ein und dann ...
lTx- erneut rekursiv lladen und Terneut xausführen.
Sie könnten also dieses kleine Snippet ausführen und interaktiv Zahlen an Ihrem Terminal eingeben und dcdann entweder die eingegebene Zahl oder den Wert für $maxden Fall, dass die eingegebene Zahl größer ist, zurückgeben. Es würde auch jede Datei (wie eine Pipe) als Standardeingabe akzeptieren . Die Lese- / Vergleichs- / Druckschleife wird fortgesetzt, bis eine leere Zeile oder ein EOF auftritt.
Einige Anmerkungen dazu - Ich habe dies geschrieben, um das Verhalten in Ihrer Shell-Funktion zu emulieren, sodass nur eine Zahl pro Zeile zuverlässig verarbeitet wird. dcEs können jedoch so viele durch Leerzeichen getrennte Zahlen pro Zeile verarbeitet werden, wie Sie darauf werfen möchten. Aufgrund seines Stapels ist jedoch die letzte Zahl in einer Zeile die erste, mit der er arbeitet, und daher dcwürde die Ausgabe , wie beschrieben, in umgekehrter Reihenfolge gedruckt, wenn Sie mehr als eine Zahl pro Zeile gedruckt / eingegeben haben um das zu handhaben, muss man eine Zeile in einem Array speichern und dann bearbeiten.
So was:
dc -e "${max}sm
[ d lm<M la 1+ d sa :a z0!=A ]SA
[ la d ;ap s0 1- d sa 0!=P ]SP
[ ? z 0=q lAx lPx l?x ]S?
[q]Sq [ s0 lm ]SM 0sa l?x"
Aber ... ich weiß nicht, ob ich das so ausführlich erklären möchte. Es genügt zu sagen, dass beim dcEinlesen jedes Werts im Stapel entweder der Wert oder der Wert des Stapels $maxin einem indizierten Array gespeichert wird. Sobald festgestellt wird, dass der Stapel wieder leer ist, wird jedes indizierte Objekt gedruckt, bevor versucht wird, ein anderes zu lesen Eingabezeile.
Und so, während das erste Skript tut ...
10 15 20 25 30 ##my input line
20
20
20
15
10 ##see what I mean?
Der zweite macht:
10 15 20 25 30 ##my input line
10 ##that's better
15
20
20 ##$max is 20 for both examples
20
Sie können mit Gleitkommazahlen beliebiger Genauigkeit umgehen, wenn Sie sie zuerst mit dem kBefehl festlegen . Und Sie können die input- oder output-Radices unabhängig voneinander ändern - was manchmal aus Gründen nützlich sein kann, die Sie vielleicht nicht erwarten. Beispielsweise:
echo 100000o 10p|dc
00010
... der zuerst dcden Ausgaberadix auf 100000 setzt und dann 10 ausgibt.