Puoi confrontare solo due numeri con dclike:
dc -e "[$1]sM $2d $1<Mp"
... dov'è il "$1"tuo valore massimo ed "$2"è il numero che stamperesti se fosse inferiore a "$1". Ciò richiede anche GNU dc, ma puoi fare la stessa cosa in modo portabile come:
dc <<MAX
[$1]sM $2d $1<Mp
MAX
In entrambi i casi precedenti puoi impostare la precisione su qualcosa di diverso da 0 (impostazione predefinita) come ${desired_precision}k. Per entrambi è anche indispensabile verificare che entrambi i valori siano sicuramente numeri perché dcpossono effettuare system()chiamate con l' !operatore.
Con il seguente piccolo script (e il successivo) dovresti verificare anche l'input - like grep -v \!|dco qualcosa del genere per gestire in modo sicuro input arbitrari. Dovresti anche sapere che dcinterpreta i numeri negativi con un _prefisso anziché con un -prefisso, poiché quest'ultimo è l'operatore di sottrazione.
A parte questo, con questo script dcleggerai tutti i \nnumeri separati di ewline sequenziali che ti piacerebbe fornirli e stamperai per ciascuno il tuo $maxvalore o l'input, a seconda di quale è il minore del guaio:
dc -e "${max}sm
[ z 0=? d lm<M p s0 lTx ]ST
[ ? z 0!=T q ]S?
[ s0 lm ]SM lTx"
Quindi ... ciascuno di tali [parentesi quadre ]distese è una dc stringa oggetto che viene SAVED ciascuna alla rispettiva matrice - qualsiasi delle T, ?o M. Oltre ad alcune altre cose che dcpotrebbero fare con una stringa , può anche xcambiarne una come macro. Se lo organizzi correttamente, un piccolo dcscript perfettamente funzionante viene assemblato in modo abbastanza semplice.
dcfunziona in pila . Tutti gli oggetti di input sono impilati uno sull'ultimo: ogni nuovo oggetto di input spinge l'ultimo oggetto in alto e tutti gli oggetti sottostanti sullo stack di uno man mano che viene aggiunto. La maggior parte dei riferimenti a un oggetto sono al valore di stack superiore, e la maggior parte i riferimenti pop che cima alla pila (che tira tutti gli oggetti sotto di esso da uno) .
Oltre allo stack principale, ci sono anche (almeno) 256 array e ogni elemento dell'array viene fornito con uno stack tutto suo. Non ne uso molto qui. Conservo semplicemente le stringhe come indicato in modo da poterle ldoverle quando desiderato ed xecute in modo condizionale, e ho sstrappato $maxil valore nella parte superiore mdell'array.
Ad ogni modo, questa piccola parte dcfa, in gran parte, ciò che fa il tuo script di shell. Utilizza l' -eopzione GNU-ism - come dcgeneralmente prende i suoi parametri da standard-in - ma potresti fare lo stesso come:
echo "$script" | cat - /dev/tty | dc
... se $scriptsembrava il bit sopra.
Funziona come:
lTx- Questo ldeve ed xecare la macro memorizzata nella parte superiore di T (per test, immagino - di solito scelgo quei nomi arbitrariamente) .
z 0=?- Test quindi verifica la profondità dello stack con / ze, se lo stack è vuoto (leggi: contiene 0 oggetti) chiama la ?macro.
? z0!=T q- La ?macro prende il nome dal ? dccomando incorporato che legge una riga di input da stdin, ma ho anche aggiunto un altro ztest di profondità dello stack, in modo che possa utilizzare ql'intero piccolo programma se inserisce una riga vuota o colpisce EOF. Ma se non lo fa !e invece popola correttamente lo stack, chiama di Tnuovo est.
d lm<M- Test eseguirà quindi l' duplicing della parte superiore dello stack e lo confronterà con $max (come memorizzato in m) . Se mè il valore minore, dcchiama la Mmacro.
s0 lm- Mfa semplicemente scoppiare la parte superiore della pila e la scarica sul manichino scalare 0- solo un modo economico per far scoppiare la pila. lDovrebbe anche remi mprima di tornare a Test.
p- Ciò significa che se mè inferiore all'attuale cima dello stack, quindi lo msostituisce (l' duplicate di esso, comunque) e viene qui pstampato, altrimenti non lo fa e qualunque cosa sia stato immesso viene pinvece stampato.
s0- Successivamente (perché pnon fa scoppiare la pila) scarichiamo di nuovo la parte superiore della pila 0e poi ...
lTx- ricorsivamente load Test ancora una volta, quindi xeseguirlo di nuovo.
Quindi potresti eseguire questo piccolo frammento e digitare in modo interattivo i numeri sul tuo terminale e dcstamparti o il numero inserito o il valore di $maxse il numero digitato fosse più grande. Accetterebbe anche qualsiasi file (come una pipe) come input standard. Continuerà il ciclo di lettura / confronto / stampa fino a quando non incontra una riga vuota o EOF.
Alcune note su questo però - ho scritto questo solo per emulare il comportamento nella funzione della shell, quindi gestisce in modo affidabile solo un numero per riga. dcpuò, tuttavia, gestire tutti i numeri separati da spazi per riga quanti ne vorresti lanciare. Tuttavia , a causa della sua pila, l'ultimo numero su una riga finisce per essere il primo su cui opera, e quindi, come scritto, dcstamperebbe il suo output al contrario se tu stampassi / digitassi più di un numero per riga. gestire ciò significa memorizzare una linea in un array, quindi lavorarla.
Come questo:
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"
Ma ... non so se voglio spiegarlo con la stessa profondità. Basti dire che mentre dclegge in ogni valore nello stack memorizza il suo valore o $maxil suo valore in un array indicizzato e, una volta rilevato lo stack è ancora una volta vuoto, quindi stampa ogni oggetto indicizzato prima di provare a leggerne un altro linea di input.
E così, mentre il primo script fa ...
10 15 20 25 30 ##my input line
20
20
20
15
10 ##see what I mean?
Il secondo fa:
10 15 20 25 30 ##my input line
10 ##that's better
15
20
20 ##$max is 20 for both examples
20
Puoi gestire float di precisione arbitraria se lo imposti per la prima volta con il kcomando. E puoi modificare i nices io l' ooutput radices in modo indipendente, il che a volte può essere utile per motivi che potresti non aspettarti. Per esempio:
echo 100000o 10p|dc
00010
... che imposta prima dcil radix di output su 100000, quindi stampa 10.