Puede comparar solo dos números con me dcgusta:
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 dcpueden hacer system()llamadas con el !operador.
Con el siguiente pequeño script (y el siguiente), también debe verificar la entrada, como grep -v \!|dcalgo o algo para manejar de manera robusta la entrada arbitraria. También debe saber que dcinterpreta 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 dcleerá tantos \nnúmeros secuenciales separados por línea de cable como le gustaría proporcionarlo, e imprimirá para cada uno su $maxvalor 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 Saved cada uno a su respectiva serie - cualquiera de T, ?o M. Además de algunas otras cosas que dcpodrían hacer con una cadena , también puede xejecutar una como macro. Si lo arreglas correctamente, un pequeño dcscript completamente funcional se ensambla simplemente.
dcFunciona 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 lcargarlas cuando lo desee y xejecutarlas condicionalmente, y srasgué $maxel valor en la parte superior de la mmatriz.
De todos modos, este poquito dchace, en gran medida, lo que hace tu script de shell. Utiliza la -eopción GNU-ism , ya que dcgeneralmente toma sus parámetros de la entrada estándar, pero puede hacer lo mismo como:
echo "$script" | cat - /dev/tty | dc
... si se $scriptparecía al bit de arriba.
Funciona como:
lTx- Esto lcarga y ecupera xla macro almacenada en la parte superior de T (para prueba, supongo, generalmente elijo esos nombres arbitrariamente) .
z 0=?- Test entonces prueba la profundidad de la pila w / zy, si la pila está vacía (léase: contiene 0 objetos) llama a la ?macro.
? z0!=T q- La ?macro lleva el nombre del ? dccomando incorporado que lee una línea de entrada desde stdin, pero también le agregué otra zprueba de profundidad de pila, para que pueda qusar 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 Test.
d lm<M- Test luego dduplicará la parte superior de la pila y la comparará con $max (como está almacenada en m) . Si mes el valor menor, dcllama a la Mmacro.
s0 lm- Msolo 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 lcarga mnuevamente antes de regresar a Test.
p- Esto significa que si mes menor que la parte superior actual de la pila, entonces lo mreemplaza (el dduplicado, de todos modos) y está aquí pborrado, de lo contrario no lo hace y lo que sea que se haya pborrado la entrada .
s0- Después (porque pno hace estallar la pila) volcamos la parte superior de la pila 0nuevamente, y luego ...
lTx- lOcurre recursivamente Tuna vez más y luego xvuelva a ejecutarlo.
Por lo tanto, podría ejecutar este pequeño fragmento y escribir números de forma interactiva en su terminal e dcimprimirle el número que ingresó o el valor de $maxsi 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. dcsin 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, dcimprimirí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 dclee en cada valor de la pila, almacena su valor o $maxel 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 kcomando. Y puede alterar los iradios nput o output 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 dcla raíz de salida de 100000 y luego imprime 10.