Sie können nur zwei Zahlen mit " dc
Gefä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 dc
kö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 \!|dc
oder so etwas, um willkürliche Eingaben sicher zu handhaben. Sie sollten auch wissen, dass dc
negative Zahlen _
eher mit einem Präfix als mit einem Präfix interpretiert werden, -
da letzteres der Subtraktionsoperator ist.
Abgesehen davon dc
liest dieses Skript so viele fortlaufende \n
ewline-getrennte Zahlen ein, wie Sie bereitstellen möchten, und druckt für jeden $max
Wert 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 S
jeweils an seinem jeweiligen Array Aved - einem der T
, ?
, oder M
. Neben ein paar anderen Dingen, dc
die mit einer Zeichenfolge zu tun haben , kann sie auch x
als Makro ausgeführt werden. Wenn Sie es richtig anordnen, wird ein voll funktionsfähiges kleines dc
Skript einfach genug zusammengestellt.
dc
arbeitet 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 l
sie oad wenn wollte und e x
sie ecute bedingt, und ich s
riss $max
‚s - Wert in der Spitze des m
Arrays.
Wie auch immer, dieses kleine bisschen dc
macht im Großen und Ganzen das, was Ihr Shell-Skript macht. Es verwendet die GNU-ism- -e
Option, die im dc
Allgemeinen die Standard-In-Parameter verwendet, aber Sie können das Gleiche tun wie:
echo "$script" | cat - /dev/tty | dc
... wenn es $script
so aussieht.
Es funktioniert wie folgt:
lTx
- Dies l
lädt und x
fü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=?
- T
est testet dann die Stapeltiefe mit z
und ruft das Makro auf , wenn der Stapel leer ist (read: enthält 0 Objekte)?
.
? z0!=T q
- Das ?
Makro ist nach dem ?
dc
eingebauten Befehl benannt, der eine Eingabezeile aus stdin liest, aber ich habe ihm auch einen weiteren z
Stapeltiefen-Test hinzugefügt , damit es q
das 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 T
est erneut aufgerufen.
d lm<M
- T
est d
kopiert dann den oberen Teil des Stapels und vergleicht ihn mit $max
(wie in gespeichert m
) . Wenn m
der kleinere Wert ist, wird dc
das M
Makro aufgerufen.
s0 lm
- M
Knallt 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 l
geladen m
, bevor zu T
est zurückgekehrt wird.
p
- Dies bedeutet, dass wenn m
kleiner als die aktuelle Stapelspitze ist, diese m
ersetzt wird ( d
jedenfalls das Uplikat davon) und hier p
gedruckt wird, andernfalls wird sie nicht gedruckt, und was auch immer die Eingabe war, wird p
stattdessen gedruckt.
s0
- Danach (weil p
der Stapel nicht aufgeht) legen wir den oberen Teil des Stapels 0
wieder ein und dann ...
lTx
- erneut rekursiv l
laden und T
erneut x
ausführen.
Sie könnten also dieses kleine Snippet ausführen und interaktiv Zahlen an Ihrem Terminal eingeben und dc
dann entweder die eingegebene Zahl oder den Wert für $max
den 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. dc
Es 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 dc
wü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 dc
Einlesen jedes Werts im Stapel entweder der Wert oder der Wert des Stapels $max
in 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 k
Befehl festlegen . Und Sie können die i
nput- oder o
utput-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 dc
den Ausgaberadix auf 100000 setzt und dann 10 ausgibt.