Puoi confrontare solo due numeri con dc
like:
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é dc
possono effettuare system()
chiamate con l' !
operatore.
Con il seguente piccolo script (e il successivo) dovresti verificare anche l'input - like grep -v \!|dc
o qualcosa del genere per gestire in modo sicuro input arbitrari. Dovresti anche sapere che dc
interpreta i numeri negativi con un _
prefisso anziché con un -
prefisso, poiché quest'ultimo è l'operatore di sottrazione.
A parte questo, con questo script dc
leggerai tutti i \n
numeri separati di ewline sequenziali che ti piacerebbe fornirli e stamperai per ciascuno il tuo $max
valore 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 S
AVED ciascuna alla rispettiva matrice - qualsiasi delle T
, ?
o M
. Oltre ad alcune altre cose che dc
potrebbero fare con una stringa , può anche x
cambiarne una come macro. Se lo organizzi correttamente, un piccolo dc
script perfettamente funzionante viene assemblato in modo abbastanza semplice.
dc
funziona 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 l
doverle quando desiderato ed x
ecute in modo condizionale, e ho s
strappato $max
il valore nella parte superiore m
dell'array.
Ad ogni modo, questa piccola parte dc
fa, in gran parte, ciò che fa il tuo script di shell. Utilizza l' -e
opzione GNU-ism - come dc
generalmente prende i suoi parametri da standard-in - ma potresti fare lo stesso come:
echo "$script" | cat - /dev/tty | dc
... se $script
sembrava il bit sopra.
Funziona come:
lTx
- Questo l
deve ed x
ecare la macro memorizzata nella parte superiore di T
(per test, immagino - di solito scelgo quei nomi arbitrariamente) .
z 0=?
- T
est quindi verifica la profondità dello stack con / z
e, se lo stack è vuoto (leggi: contiene 0 oggetti) chiama la ?
macro.
? z0!=T q
- La ?
macro prende il nome dal ?
dc
comando incorporato che legge una riga di input da stdin, ma ho anche aggiunto un altro z
test di profondità dello stack, in modo che possa utilizzare q
l'intero piccolo programma se inserisce una riga vuota o colpisce EOF. Ma se non lo fa !
e invece popola correttamente lo stack, chiama di T
nuovo est.
d lm<M
- T
est eseguirà quindi l' d
uplicing della parte superiore dello stack e lo confronterà con $max
(come memorizzato in m
) . Se m
è il valore minore, dc
chiama la M
macro.
s0 lm
- M
fa semplicemente scoppiare la parte superiore della pila e la scarica sul manichino scalare 0
- solo un modo economico per far scoppiare la pila. l
Dovrebbe anche remi m
prima di tornare a T
est.
p
- Ciò significa che se m
è inferiore all'attuale cima dello stack, quindi lo m
sostituisce (l' d
uplicate di esso, comunque) e viene qui p
stampato, altrimenti non lo fa e qualunque cosa sia stato immesso viene p
invece stampato.
s0
- Successivamente (perché p
non fa scoppiare la pila) scarichiamo di nuovo la parte superiore della pila 0
e poi ...
lTx
- ricorsivamente l
oad T
est ancora una volta, quindi x
eseguirlo di nuovo.
Quindi potresti eseguire questo piccolo frammento e digitare in modo interattivo i numeri sul tuo terminale e dc
stamparti o il numero inserito o il valore di $max
se 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. dc
può, 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, dc
stamperebbe 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 dc
legge in ogni valore nello stack memorizza il suo valore o $max
il 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 k
comando. E puoi modificare i nices i
o l' o
output 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 dc
il radix di output su 100000, quindi stampa 10.