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.
dc
, um es auf Trab zu halten.dc
ist ein launisches Biest, aber es ist vielleicht das schnellste und seltsamste gemeinsame Dienstprogramm auf jedem Unix-System. Wenn es gepaart wirdsed
, kann es einige außergewöhnliche Dinge bewirken. Ich habe damit gespielt und indd
letzter Zeit, damit ich die Monstrosität, die es gibt, ersetzen kannreadline
. Hier ist eine kleine Auswahl von Dingen, die ich gemacht habe. Ein Tunrev
indc
Spielend fast Kind.[string]P91P93P[string]P
. Also habe ich dieses kleine bisschen vonsed
Ihnen vielleicht nützlich gefunden: Dassed 's/[][]/]P93]&[1P[/g;s/[]3][]][[][1[]//g'
sollte die Quadrate immer korrekt durch eine Klammer zum Schließen des Strings ersetzen, dann aP
, dann der Dezimal-Ascii-Wert des Quadrats und ein andererP
; dann eine offene[
eckige Klammer, um die Zeichenfolge fortzusetzen. Keine Ahnung, ob Sie diedc
String / Numeric-Konvertierungsfunktionen von w / durcheinandergebracht haben, aber - besonders wenn Sie mit w / kombiniert werdenod
- es kann ziemlich lustig sein.Wenn Sie wissen , dass Sie mit zwei ganzen Zahlen zu tun
a
undb
dann diesen einfachen Shell arithmetische Erweiterungen des ternären Operator ausreichen , um den numerischen max zu geben:und numerische min:
Z.B
Hier ist ein Shell-Skript, das dies demonstriert:
quelle
max=$(( a >= b ? a : b ))
, aber das Ergebnis ist völlig dasselbe - wenn a und b gleich sind, spielt es keine Rolle, welches Ergebnis zurückgegeben wird. Ist es das, was du fragst?if (( a >= b )); then echo a is greater than or equal to b; fi
- ist es das, wonach du fragst ? (Beachten Sie die Verwendung von(( ))
hier anstelle von$(( ))
)sort
undhead
kann dies tun:quelle
O(n log(n))
zwar eine effiziente Implementierung von max wäreO(n)
. Es ist jedoch unsere geringe Bedeutungn=2
, da das Laichen von zwei Prozessen viel mehr Aufwand bedeutet.numbers="1 4 3 5 7 1 10 21 8";
echo $numbers | tr ' ' "\n" | sort -rn | head -n 1
max=0; for x in $numbers ; do test $x -gt $max && max=$x ; done
Sie können eine Bibliothek vordefinierter mathematischer Funktionen für definieren
bc
und diese dann in der Befehlszeile verwenden.Zum Beispiel ist die folgende in einer Textdatei wie
~/MyExtensions.bc
:Jetzt können Sie anrufen
bc
durch:Zu Ihrer Information, es gibt kostenlose mathematische Bibliotheksfunktionen wie diese, die online verfügbar sind.
Mit Hilfe dieser Datei können Sie leicht ausrechnen , kompliziertere Funktionen wie
GCD
:quelle
bc
sind nurdc
Frontends bis zum heutigen Tag, auch wenn GNUbc
nicht mehr so ist (aber GNUdc
und GNUbc
teilen eine erstaunliche Menge ihrer Codebasis) . Auf jeden Fall könnte dies hier die beste Antwort sein.bc
auch direkt vor dem Funktionsaufruf an leiten. Keine zweite Datei benötigt dann :)Zu lange für einen Kommentar:
Während Sie diese Dinge z. B. mit
sort | head
oder tun könnensort | tail
, scheint dies sowohl in Bezug auf Ressourcen als auch in Bezug auf die Fehlerbehandlung suboptimal zu sein. Bei der Ausführung bedeutet die Kombination, dass zwei Prozesse erzeugt werden, um nur zwei Zeilen zu überprüfen. Das scheint ein bisschen übertrieben zu sein.Das ernstere Problem ist, dass Sie in den meisten Fällen wissen müssen, dass die Eingabe vernünftig ist, dh nur Zahlen enthält. @glennjackmanns Lösung löst dies geschickt, da
printf %d
auf Nicht-Ganzzahlen verzichtet werden sollte. Es funktioniert auch nicht mit Gleitkommazahlen (es sei denn, Sie ändern den Formatbezeichner in%f
, wodurch Sie auf Rundungsprobleme stoßen).test $1 -gt $2
zeigt an, ob der Vergleich fehlgeschlagen ist oder nicht (Exit-Status 2 bedeutet, dass während des Tests ein Fehler aufgetreten ist. Da dies normalerweise eine integrierte Shell ist, wird kein zusätzlicher Prozess erzeugt - wir sprechen von Hunderten mal schnellere Ausführung. Funktioniert jedoch nur mit ganzen Zahlen.Wenn Sie zufällig ein paar Gleitkommazahlen vergleichen müssen, könnte die
bc
folgende Option interessant sein :wäre gleichbedeutend mit
test $1 -gt $2
und mit in in shell:ist immer noch fast 2,5 mal schneller als
printf | sort | head
(für zwei Nummern).Wenn Sie sich auf GNU-Erweiterungen verlassen können
bc
, können Sie auch dieread()
Funktion verwenden, um die Zahlen direkt in dasbc
Skript einzulesen.quelle
dc -e "${max}sm[z0=?dlm<Mps0lTx]ST[?z0!=Tq]S?[s0lm]SMlTx"
- oh, außer dasdc
macht das Ganze (außer das Echo, obwohl es das könnte) - es liest stdin und druckt entweder$max
oder die eingegebene Nummer, je nachdem welche ist kleiner. Wie auch immer, es ist mir eigentlich egal, und deine Antwort ist besser, als ich schreiben wollte. Also, bitte, hab mein Votum.dc
Skript zu haben wäre wirklich nett, RPN wird heutzutage nicht mehr so oft gesehen.dc
Sie die E / A alleine ausführen können, ist sie noch eleganter als.Um den größeren Wert von $ a und $ b zu erhalten, verwenden Sie Folgendes:
Aber Sie brauchen etwas in der Nähe, wahrscheinlich wollen Sie die Zahl nicht ausführen, also verwenden Sie "echo", um den größeren Wert der beiden anzuzeigen.
Das obige passt gut in eine Shell-Funktion, z
Verwenden Sie diese geänderte Version, um die größere der beiden Variablen zuzuweisen:
oder benutze die definierte Funktion:
Die Funktionsvariante gibt Ihnen auch die Möglichkeit, die Eingabefehlerprüfung übersichtlich hinzuzufügen.
Um das Maximum von zwei Dezimal- / Gleitkommazahlen zurückzugeben, können Sie verwenden
awk
BEARBEITEN: Mit dieser Technik können Sie eine "Limit" -Funktion erstellen, die umgekehrt wie in Ihrer Bearbeitung / Notiz funktioniert. Diese Funktion gibt die niedrigere der beiden zurück, zB:
Ich mag es, Utility-Funktionen in eine separate Datei zu packen, sie aufzurufen
myprogram.funcs
und in einem Skript wie folgt zu verwenden:FWIW dies macht immer noch das, was Sie getan haben, und Ihre Version ist genauso effizient, obwohl sie ausführlicher ist.
Die kompaktere Form ist nicht wirklich besser, verhindert jedoch Unordnung in Ihren Skripten. Wenn Sie viele einfache if-then-else-fi-Konstrukte haben, wird das Skript schnell erweitert.
Wenn Sie die Prüfung für größere / kleinere Zahlen mehrmals in einem einzelnen Skript verwenden möchten, fügen Sie sie in eine Funktion ein. Das Funktionsformat erleichtert das Debuggen und Wiederverwenden und ermöglicht das einfache Ersetzen dieses Teils des Skripts, beispielsweise durch einen awk-Befehl, um nicht ganzzahlige Dezimalzahlen verarbeiten zu können.
Wenn es sich um einen Einzelfall handelt, codieren Sie ihn einfach in der Zeile.
quelle
Sie können eine Funktion definieren als
Nennen Sie es wie
maxnum 54 42
und es hallt54
. Sie können Validierungsinformationen in die Funktion einfügen (z. B. zwei Argumente oder Zahlen als Argumente), wenn Sie möchten.quelle
function maxnum {
zumaxnum() {
und es wird für viel mehr Muscheln funktionieren.In einem Shell-Skript können Sie eine beliebige öffentliche statische Java-Methode (und beispielsweise Math.min () ) verwenden. Von Bash unter Linux:
Dies erfordert Java Shell Bridge https://sourceforge.net/projects/jsbridge/
Sehr schnell, da die Methodenaufrufe werden intern geleitet ; Kein Prozess erforderlich.
quelle
Die meisten Leute würden nur tun
sort -n input | head -n1
(oder schwänzen), es ist gut genug für die meisten Skriptsituationen. Dies ist jedoch etwas umständlich, wenn Sie Zahlen in einer Zeile anstelle einer Spalte haben - Sie müssen sie in einem geeigneten Format (tr ' ' '\n'
oder ähnlichem) ausdrucken .Shells sind nicht gerade ideal für die numerische Verarbeitung, aber Sie können ganz einfach ein anderes Programm aufrufen, das besser darin ist. Abhängig von Ihrer eigenen Präferenz können Sie maximal anrufen
dc
(etwas verschleiert, aber wenn Sie wissen, was Sie tun, ist das in Ordnung - siehe Antwort von mikeserv) oderawk 'NR==1{max=$1} {if($1>max){max=$1}} END { print max }'
. Oder vielleichtperl
oderpython
wenn Sie es vorziehen. Eine Lösung (wenn Sie bereit sind, weniger bekannte Software zu installieren und zu verwenden) wäreised
(insbesondere, wenn sich Ihre Daten in einer einzigen Zeile befinden: Sie müssen nur tunised --l input.dat 'max$1'
).Weil Sie nach zwei Zahlen fragen, ist das alles übertrieben. Das sollte reichen:
quelle
sys.argv
python2 -c 'import sys; print (max(sys.argv))' "$@"
sort + head
die übertrieben sind, aberpython
nicht berechnet werden.python
weil es ordentlich ist.python
Frömmler (oder weil es nicht eine Gabel erfordert und einen zusätzlichen gigantischen Dolmetscher) . Oder vielleicht beides.