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.
dc
embargo, tal vez solo coloque algunos números de vez en cuando para mantenerlo alerta.dc
es 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 unarev
endc
casi un juego de niños.[string]P91P93P[string]P
. Entonces, tengo un poco de estosed
que 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 condc
las 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
a
yb
, 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$(( ))
)sort
yhead
puede hacer esto:fuente
O(n log(n))
mientras que una implementación eficiente de max seríaO(n)
. Sinn=2
embargo, 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 1
max=0; for x in $numbers ; do test $x -gt $max && max=$x ; done
Puede definir una biblioteca de funciones matemáticas predefinidas para
bc
luego usarlas en la línea de comandos.Por ejemplo, incluya lo siguiente en un archivo de texto como
~/MyExtensions.bc
:Ahora puedes llamar
bc
por: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
bc
mensajes de texto son solodc
front-end hasta el día de hoy, incluso si GNUbc
ya no es así (pero GNUdc
y GNUbc
comparten 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 | head
osort | 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 %d
deberí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 $2
le 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 $2
y 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 elbc
sript.fuente
dc -e "${max}sm[z0=?dlm<Mps0lTx]ST[?z0!=Tq]S?[s0lm]SMlTx"
- oh, excepto que esodc
hace todo (excepto el eco, aunque podría) - lee stdin e imprime cualquiera$max
o 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.dc
script explicado sería realmente bueno, RPN no se ve tan a menudo en estos días.dc
puede 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
awk
EDITAR: 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.funcs
y 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 42
y 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 posiblementeperl
opython
si 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.argv
python2 -c 'import sys; print (max(sys.argv))' "$@"
sort + head
son excesivos peropython
no lo son no computan.python
porque es ordenada.python
intolerante (o porque no requiere un tenedor y un intérprete gigantesco adicional) . O tal vez ambos.