Puede comparar solo dos números con me dc
gusta:
dc -e "[$1]sM $2d $1<Mp"
... dónde "$1"
está su valor máximo y "$2"
es el número que imprimiría si es menor que "$1"
. Eso también requiere GNU dc
, pero puede hacer lo mismo de forma portátil como:
dc <<MAX
[$1]sM $2d $1<Mp
MAX
En los dos casos anteriores, puede establecer la precisión en algo diferente a 0 (el valor predeterminado) como ${desired_precision}k
. Para ambos, también es imprescindible que verifique que ambos valores son definitivamente números porque dc
pueden hacer system()
llamadas con el !
operador.
Con el siguiente pequeño script (y el siguiente), también debe verificar la entrada, como grep -v \!|dc
algo o algo para manejar de manera robusta la entrada arbitraria. También debe saber que dc
interpreta los números negativos con un _
prefijo en lugar de un -
prefijo, porque este último es el operador de resta.
Aparte de eso, con este script dc
leerá tantos \n
números secuenciales separados por línea de cable como le gustaría proporcionarlo, e imprimirá para cada uno su $max
valor o la entrada, dependiendo de cuál sea el menor de los wo:
dc -e "${max}sm
[ z 0=? d lm<M p s0 lTx ]ST
[ ? z 0!=T q ]S?
[ s0 lm ]SM lTx"
Así que ... cada uno de esos [
corchetes cuadrados ]
extensiones es una dc
cadena de objeto que se S
aved cada uno a su respectiva serie - cualquiera de T
, ?
o M
. Además de algunas otras cosas que dc
podrían hacer con una cadena , también puede x
ejecutar una como macro. Si lo arreglas correctamente, un pequeño dc
script completamente funcional se ensambla simplemente.
dc
Funciona en una pila . Todos los objetos de entrada se apilan cada uno sobre el último: cada nuevo objeto de entrada empuja el último objeto superior y todos los objetos debajo de él en la pila uno a medida que se agrega. La mayoría de las referencias a un objeto son al valor de la pila superior, y la mayoría de las referencias resaltan esa parte superior de la pila (que tira todos los objetos debajo de uno hacia arriba) .
Además de la pila principal, también hay (al menos) 256 matrices y cada elemento de la matriz viene con una pila propia. No uso mucho de eso aquí. Simplemente almaceno las cadenas como se menciona para poder l
cargarlas cuando lo desee y x
ejecutarlas condicionalmente, y s
rasgué $max
el valor en la parte superior de la m
matriz.
De todos modos, este poquito dc
hace, en gran medida, lo que hace tu script de shell. Utiliza la -e
opción GNU-ism , ya que dc
generalmente toma sus parámetros de la entrada estándar, pero puede hacer lo mismo como:
echo "$script" | cat - /dev/tty | dc
... si se $script
parecía al bit de arriba.
Funciona como:
lTx
- Esto l
carga y ecupera x
la macro almacenada en la parte superior de T
(para prueba, supongo, generalmente elijo esos nombres arbitrariamente) .
z 0=?
- T
est entonces prueba la profundidad de la pila w / z
y, si la pila está vacía (léase: contiene 0 objetos) llama a la ?
macro.
? z0!=T q
- La ?
macro lleva el nombre del ?
dc
comando incorporado que lee una línea de entrada desde stdin, pero también le agregué otra z
prueba de profundidad de pila, para que pueda q
usar todo el pequeño programa si tira de una línea en blanco o golpea EOF. Pero si no lo hace !
y en su lugar llena la pila con éxito, vuelve a llamar a T
est.
d lm<M
- T
est luego d
duplicará la parte superior de la pila y la comparará con $max
(como está almacenada en m
) . Si m
es el valor menor, dc
llama a la M
macro.
s0 lm
- M
solo hace estallar la parte superior de la pila y la descarga al escalar ficticio 0
, solo una forma barata de hacer estallar la pila. También se l
carga m
nuevamente antes de regresar a T
est.
p
- Esto significa que si m
es menor que la parte superior actual de la pila, entonces lo m
reemplaza (el d
duplicado, de todos modos) y está aquí p
borrado, de lo contrario no lo hace y lo que sea que se haya p
borrado la entrada .
s0
- Después (porque p
no hace estallar la pila) volcamos la parte superior de la pila 0
nuevamente, y luego ...
lTx
- l
Ocurre recursivamente T
una vez más y luego x
vuelva a ejecutarlo.
Por lo tanto, podría ejecutar este pequeño fragmento y escribir números de forma interactiva en su terminal e dc
imprimirle el número que ingresó o el valor de $max
si el número que escribió fue mayor. También aceptaría cualquier archivo (como una tubería) como entrada estándar. Continuará el ciclo de lectura / comparación / impresión hasta que encuentre una línea en blanco o EOF.
Sin embargo, algunas notas sobre esto: escribí esto solo para emular el comportamiento en su función de shell, por lo que solo maneja de manera robusta un número por línea. dc
sin embargo, puede manejar tantos números separados por espacios por línea como desee lanzarle. Sin embargo , debido a su pila, el último número en una línea termina siendo el primero en el que opera, por lo que, tal como está escrito, dc
imprimiría su salida en reversa si imprimiera / escribiera más de un número por línea. manejar eso es almacenar una línea en una matriz y luego trabajarla.
Me gusta esto:
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"
Pero ... No sé si quiero explicar eso con tanta profundidad. Baste decir que, a medida que se dc
lee en cada valor de la pila, almacena su valor o $max
el valor de ella en una matriz indexada y, una vez que detecta que la pila está nuevamente vacía, imprime cada objeto indexado antes de intentar leer otro línea de entrada.
Y así, mientras que el primer guión sí ...
10 15 20 25 30 ##my input line
20
20
20
15
10 ##see what I mean?
El segundo hace:
10 15 20 25 30 ##my input line
10 ##that's better
15
20
20 ##$max is 20 for both examples
20
Puede manejar flotantes de precisión arbitraria si primero lo configura con el k
comando. Y puede alterar los i
radios nput o o
utput de forma independiente, lo que a veces puede ser útil por razones que podría no esperar. Por ejemplo:
echo 100000o 10p|dc
00010
... que primero establece dc
la raíz de salida de 100000 y luego imprime 10.