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.
dcembargo, tal vez solo coloque algunos números de vez en cuando para mantenerlo alerta.dces una bestia voluble, pero podría ser la utilidad común más rápida y extrañamente capaz en cualquier sistema Unix. Cuando se combina consedél, puede hacer algunas cosas extraordinarias. He estado jugando con él yddúltimamente para poder reemplazar la monstruosidad que esreadline. Aquí hay una pequeña muestra de algunas cosas que he estado haciendo. Haciendo unarevendccasi un juego de niños.[string]P91P93P[string]P. Entonces, tengo un poco de estosedque puede ser útil:sed 's/[][]/]P93]&[1P[/g;s/[]3][]][[][1[]//g'que siempre debe reemplazar los cuadrados correctamente con un corchete de cierre de cadena, luego aP, luego el valor decimal ascii del cuadrado y otroP; luego un[corchete abierto para continuar la cuerda. No sé si ha jugado condclas capacidades de conversión de cadena / numérico de w / , pero, especialmente cuando se combina con w /od, puede ser bastante divertido.Si sabe que está tratando con dos enteros
ayb, entonces estas expansiones aritméticas de shell simples que usan el operador ternario son suficientes para dar el máximo numérico:y min numérico:
P.ej
Aquí hay un script de shell que demuestra esto:
fuente
max=$(( a >= b ? a : b )), pero el resultado es completamente el mismo: si a y b son iguales, entonces realmente no importa cuál se devuelva. ¿Es eso lo que estás preguntando?if (( a >= b )); then echo a is greater than or equal to b; fi: ¿es eso lo que estás pidiendo? (tenga en cuenta el uso de(( ))aquí en lugar de$(( )))sortyheadpuede hacer esto:fuente
O(n log(n))mientras que una implementación eficiente de max seríaO(n). Sinn=2embargo, es nuestra pequeña importancia , ya que la generación de dos procesos es mucho más grande.numbers="1 4 3 5 7 1 10 21 8";echo $numbers | tr ' ' "\n" | sort -rn | head -n 1max=0; for x in $numbers ; do test $x -gt $max && max=$x ; donePuede definir una biblioteca de funciones matemáticas predefinidas para
bcluego usarlas en la línea de comandos.Por ejemplo, incluya lo siguiente en un archivo de texto como
~/MyExtensions.bc:Ahora puedes llamar
bcpor:Para su información, hay funciones gratuitas de biblioteca matemática como esta disponible en línea.
Usando ese archivo, puede calcular fácilmente funciones más complicadas como
GCD:fuente
bcmensajes de texto son solodcfront-end hasta el día de hoy, incluso si GNUbcya no es así (pero GNUdcy GNUbccomparten una cantidad prodigiosa de su base de código) . De todos modos, esta podría ser la mejor respuesta aquí.bc, justo antes de la llamada a la función. No se necesita entonces segundo archivo :)Demasiado tiempo para un comentario:
Si bien puede hacer estas cosas, por ejemplo, con los combos
sort | headosort | tail, parece bastante subóptimo en cuanto a recursos y manejo de errores. En lo que respecta a la ejecución, el combo significa generar 2 procesos solo para verificar dos líneas. Eso parece ser un poco exagerado.El problema más grave es que, en la mayoría de los casos, debe saber que la entrada es correcta, es decir, contiene solo números. La solución de @ glennjackmann resuelve inteligentemente esto, ya que
printf %ddebería vomitar en los no enteros. Tampoco funcionará con flotantes (a menos que cambie el especificador de formato a%f, donde se encontrará con problemas de redondeo).test $1 -gt $2le dará una indicación de si la comparación falló o no (el estado de salida de 2 significa que hubo un error durante la prueba. Dado que esto generalmente es un shell incorporado, no se genera ningún proceso adicional; estamos hablando de un orden de cientos veces una ejecución más rápida. Sin embargo, solo funciona con enteros.Si tiene que comparar un par de números de coma flotante, una opción interesante podría ser
bc:sería el equivalente de
test $1 -gt $2y en in in shell:sigue siendo casi 2,5 veces más rápido que
printf | sort | head(para dos números).Si puede confiar en las extensiones de GNU
bc, entonces también puede usar laread()función para leer los números directamente en elbcsript.fuente
dc -e "${max}sm[z0=?dlm<Mps0lTx]ST[?z0!=Tq]S?[s0lm]SMlTx"- oh, excepto que esodchace todo (excepto el eco, aunque podría) - lee stdin e imprime cualquiera$maxo el número de entrada dependiendo de qué es más pequeño. De todos modos, no me importa explicarlo y tu respuesta es mejor de lo que iba a escribir. Así que ten mi voto a favor, por favor.dcscript explicado sería realmente bueno, RPN no se ve tan a menudo en estos días.dcpuede hacer la E / S por sí mismo, sería aún más elegante que.Para obtener el mayor valor de $ a y $ b, use esto:
Pero necesitas algo alrededor de eso, probablemente no quieras ejecutar el número, así que para mostrar el mayor valor de los dos usa "echo"
Lo anterior encaja perfectamente en una función de shell, por ejemplo
Para asignar la mayor de las dos a variable, use esta versión modificada:
o use la función definida:
La variación de la función también le brinda la oportunidad de agregar la comprobación de errores de entrada de forma ordenada.
Para devolver el máximo de dos números decimales / coma flotante, puede usar
awkEDITAR: Con esta técnica, puede crear una función de "límite" que opera al revés según su edición / nota. Esta función devolverá la menor de las dos, por ejemplo:
Me gusta poner las funciones de utilidad en un archivo separado, llamarlo
myprogram.funcsy usarlo en un script de la siguiente manera:FWIW sigue haciendo lo que hiciste, y tu versión, aunque es más detallada, es igual de eficiente.
La forma más compacta no es realmente mejor, pero evita el desorden en sus scripts. Si tiene muchas construcciones simples de if-then-else-fi, el script se expande rápidamente.
Si desea reutilizar el cheque para números más grandes / más pequeños varias veces en un solo script, póngalo en una función. El formato de función facilita la depuración y la reutilización y le permite reemplazar fácilmente esa parte del script, por ejemplo, con un comando awk para poder manejar números decimales no enteros.
Si es un caso de uso único, solo codifíquelo en línea.
fuente
Puede definir una función como
Llámalo como
maxnum 54 42y hace eco54. Puede agregar información de validación dentro de la función (como dos argumentos o números como argumentos) si lo desea.fuente
function maxnum {amaxnum() {y funcionará para muchos más proyectiles.Desde un script de shell, hay una manera de usar cualquier método estático público de Java (y, por ejemplo, Math.min () ). De bash en Linux:
Esto requiere Java Shell Bridge https://sourceforge.net/projects/jsbridge/
Muy rápido, porque las llamadas al método se canalizan internamente ; No se requiere proceso.
fuente
La mayoría de la gente simplemente haría
sort -n input | head -n1(o cola), es lo suficientemente bueno para la mayoría de las situaciones de secuencias de comandos. Sin embargo, esto es un poco torpe si tiene números en una línea en lugar de una columna; debe imprimirlo en un formato adecuado (tr ' ' '\n'o algo similar).Los shells no son exactamente ideales para el procesamiento numérico, pero puede simplemente conectarse a otro programa que sea mejor. Dependiendo de su propia preferencia, puede llamar al máximo
dc(un poco ofuscado, pero si sabe lo que está haciendo, está bien, vea la respuesta de mikeserv), oawk 'NR==1{max=$1} {if($1>max){max=$1}} END { print max }'. O posiblementeperlopythonsi lo prefieres. Una solución (si está dispuesto a instalar y usar un software menos conocido) seríaised(especialmente si sus datos están en una sola línea: solo tiene que hacerloised --l input.dat 'max$1').Debido a que está pidiendo dos números, todo esto es exagerado. Esto debería ser suficiente:
fuente
sys.argvpython2 -c 'import sys; print (max(sys.argv))' "$@"sort + headson excesivos peropythonno lo son no computan.pythonporque es ordenada.pythonintolerante (o porque no requiere un tenedor y un intérprete gigantesco adicional) . O tal vez ambos.