Vous pouvez comparer seulement deux nombres avec dc
comme:
dc -e "[$1]sM $2d $1<Mp"
... où "$1"
est votre valeur maximale et "$2"
le nombre que vous imprimeriez s'il était inférieur à "$1"
. Cela nécessite également GNU dc
- mais vous pouvez faire la même chose de manière portable comme:
dc <<MAX
[$1]sM $2d $1<Mp
MAX
Dans les deux cas ci - dessus , vous pouvez définir la précision autre chose que 0 (la valeur par défaut) comme ${desired_precision}k
. Pour les deux, il est également impératif de vérifier que les deux valeurs sont bien des nombres car vous dc
pouvez effectuer des system()
appels avec l' !
opérateur.
Avec le petit script suivant (et le suivant), vous devez également vérifier l’entrée - comme grep -v \!|dc
un outil permettant de gérer de manière robuste une entrée arbitraire. Vous devez également savoir que dc
interprète les nombres négatifs avec un _
préfixe plutôt qu'un -
préfixe - car ce dernier est l'opérateur de soustraction.
En plus de cela, avec ce script dc
, vous lirez autant de nombres séquentiels \n
séparés par ligne électronique que vous voudriez bien le fournir, et vous imprimerez pour chacun votre $max
valeur ou l'entrée, selon le plus petit des deux:
dc -e "${max}sm
[ z 0=? d lm<M p s0 lTx ]ST
[ ? z 0!=T q ]S?
[ s0 lm ]SM lTx"
Alors ... chacun de ces [
carrés bracketing ]
étendues est une dc
chaîne objet qui est S
Aved chacun à son réseau respectif - l'une des T
, ?
ou M
. À part quelques petites choses que l’on dc
pourrait faire avec une chaîne , elle peut aussi être x
utilisée comme une macro. Si vous organisez cela correctement, un petit dc
script entièrement fonctionnel est assemblé de manière assez simple.
dc
fonctionne sur une pile . Tous les objets en entrée sont empilés les uns sur les autres - chaque nouvel objet en entrée repoussant le dernier objet en haut et tous les objets en dessous de celui-ci, un par un au fur et à mesure de son ajout. La plupart des références à un objet se rapportent à la valeur de pile supérieure, et la plupart des références insèrent cette pile en haut de la pile (qui extrait tous les objets situés en dessous d'un objet) .
En plus de la pile principale, il y a aussi (au moins) 256 tableaux et chaque élément de tableau est livré avec une pile qui lui est propre. Je n'en utilise pas beaucoup ici. Je stocke simplement les chaînes comme indiqué afin de pouvoir les l
utiliser quand bon me semble et les x
échanger sous condition, et j’ai s
déchiré $max
la valeur en haut du m
tableau.
Quoi qu'il en soit, ce petit peu dc
fait, en grande partie, ce que fait votre script shell. Il utilise l' -e
option GNU-ism - comme dc
ses paramètres sont généralement pris dans l'entrée standard - mais vous pouvez faire la même chose de la manière suivante:
echo "$script" | cat - /dev/tty | dc
... Si $script
ressemblait à ce qui précède.
Cela fonctionne comme:
lTx
- Cela permet d' l
exécuter et d' x
exécuter la macro stockée dans le haut de T
(pour tester, je suppose - je choisis habituellement ces noms de manière arbitraire) .
z 0=?
- T
est ensuite teste la profondeur de la pile w / z
et, si la pile est vide (read: contient 0 objets), elle appelle la ?
macro.
? z0!=T q
- La ?
macro porte le nom de la ?
dc
commande intégrée qui lit une ligne d’entrée à partir de stdin, mais j’y ai également ajouté un autre z
test de profondeur de la pile, de sorte qu’elle puisse q
gérer tout le petit programme s’il affiche une ligne vierge ou atteint EOF. Mais si ce n'est !
pas le cas et que la pile est correctement remplie, elle appelle à T
nouveau est.
d lm<M
- T
est alors va d
utiliser le haut de la pile et le comparer à $max
(tel que stocké dans m
) . Si m
est la plus petite valeur, dc
appelle la M
macro.
s0 lm
- M
affiche simplement le haut de la pile et le vide dans le scalaire factice 0
- juste un moyen peu coûteux de faire éclater la pile. Il a également l
OADS à m
nouveau avant de revenir à T
est.
p
- Cela signifie que si m
est inférieur au sommet actuel de la pile, il le m
remplace (son d
uplicate, en tout cas) et est ici p
imprimé, sinon ce n'est pas le cas et quelle que soit l'entrée, il est p
imprimé à la place.
s0
- Ensuite (parce p
que la pile n'apparaît pas), nous vidons à nouveau le haut de la pile 0
, puis ...
lTx
- récursive l
OAD T
HNE fois plus de e x
ecute nouveau.
Ainsi, vous pouvez exécuter ce petit extrait et taper les numéros de manière interactive sur votre terminal et vous dc
imprimer le numéro que vous avez entré ou la valeur de $max
si le nombre que vous avez entré est plus grand. Il accepterait également n'importe quel fichier (tel qu'un tuyau) comme entrée standard. La boucle lecture / comparaison / impression se poursuivra jusqu'à ce qu'elle rencontre une ligne vierge ou une fin de fichier.
Quelques notes à ce sujet, par contre - j’ai écrit ceci uniquement pour émuler le comportement de votre fonction shell, afin qu’il ne gère que de manière robuste le nombre par ligne. dc
peut cependant traiter autant de numéros d'espaces séparés par ligne que vous le souhaitez. Cependant , à cause de sa pile, le dernier chiffre d’une ligne devient le premier sur lequel il opère et, ainsi qu’il est écrit, dc
il imprimerait sa sortie en sens inverse si vous imprimiez / tapiez plus d’un nombre par ligne. gérer cela consiste à stocker une ligne dans un tableau, puis à la travailler.
Comme ça:
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"
Mais ... je ne sais pas si je veux expliquer cela plus en profondeur. Il suffit de dire que, comme dc
chaque valeur de la pile est lue, elle stocke sa valeur ou sa valeur $max
dans un tableau indexé et, une fois détectée, la pile est à nouveau vide, elle affiche ensuite chaque objet indexé avant de tenter d'en lire un autre. ligne d'entrée.
Et alors, alors que le premier script fait ...
10 15 20 25 30 ##my input line
20
20
20
15
10 ##see what I mean?
La seconde fait:
10 15 20 25 30 ##my input line
10 ##that's better
15
20
20 ##$max is 20 for both examples
20
Vous pouvez gérer des flottants de précision arbitraire si vous le définissez d'abord avec la k
commande. Et vous pouvez modifier les radices d' i
entrée ou de o
sortie de manière indépendante - ce qui peut parfois être utile pour des raisons inattendues. Par exemple:
echo 100000o 10p|dc
00010
... qui définit d dc
' abord le radix de sortie à 100000, puis en imprime 10.
dc
fois de temps en temps pour le garder sur ses gardes, cependant.dc
c'est une bête volage, mais il pourrait bien être l'utilitaire commun le plus rapide et le plus étrangement capable sur n'importe quel système Unix. Lorsque jumelé avecsed
peut faire des choses extraordinaires. J'ai joué avec etdd
récemment pour pouvoir remplacer la monstruosité qui estreadline
. Voici un petit échantillon de certaines choses que j'ai faites. Faire unrev
dansdc
est presque un jeu d'enfant.[string]P91P93P[string]P
. Donc, j'ai ce petit bout desed
chose que vous pourriez trouver utile:sed 's/[][]/]P93]&[1P[/g;s/[]3][]][[][1[]//g'
qui devrait toujours remplacer les carrés correctement par un crochet de fermeture de chaîne, puis unP
, puis la valeur décimale ascii du carré et un autreP
; puis un[
crochet ouvert pour continuer la chaîne. Je ne sais pas si vous avez déconné avecdc
les capacités de conversion chaîne / numérique de w / , mais - surtout lorsque combiné avec w /od
- cela peut être assez amusant.Si vous savez que vous avez affaire à deux entiers
a
etb
, alors ces simples développements arithmétiques en shell à l'aide de l'opérateur ternaire suffisent pour donner le max numérique:et numérique min .:
Par exemple
Voici un script shell démontrant ceci:
la source
max=$(( a >= b ? a : b ))
, mais le résultat est tout à fait le même: si a et b sont égaux, le résultat renvoyé importe peu. Est-ce ce que vous demandez?if (( a >= b )); then echo a is greater than or equal to b; fi
- c'est ce que vous demandez? (notez l'utilisation(( ))
ici au lieu de$(( ))
)sort
ethead
peut le faire:la source
O(n log(n))
une implémentation efficace de maxO(n)
.n=2
Cependant, c’est notre faible importance , car la création de deux processus représente une charge beaucoup plus importante.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
Vous pouvez définir une bibliothèque de fonctions mathématiques prédéfinies pour
bc
, puis les utiliser dans la ligne de commande.Par exemple, incluez les éléments suivants dans un fichier texte tel que
~/MyExtensions.bc
:Maintenant, vous pouvez appeler
bc
par:Pour votre information, il existe des fonctions gratuites de la bibliothèque mathématique comme celle-ci disponibles en ligne.
En utilisant ce fichier, vous pouvez facilement calculer des fonctions plus complexes telles que
GCD
:la source
bc
s ne sont plus que desdc
interfaces à ce jour, même si GNUbc
ne l’est plus (mais GNUdc
et GNUbc
partagent une quantité prodigieuse de leur base de code) . Quoi qu'il en soit, cela pourrait être la meilleure réponse ici.bc
, juste avant l'appel de la fonction. Pas de deuxième fichier nécessaire alors :)Trop long pour un commentaire:
Bien que vous puissiez faire ces choses, par exemple avec les combinaisons
sort | head
ousort | tail
, cela semble plutôt sous-optimal en termes de gestion des ressources et d'erreur. En ce qui concerne l'exécution, la liste déroulante signifie que deux processus sont créés pour vérifier deux lignes. Cela semble être un peu exagéré.Le problème le plus grave est que, dans la plupart des cas, vous devez savoir que l'entrée est saine, c'est-à-dire qu'elle ne contient que des chiffres. La solution de @ glennjackmann résout intelligemment ce problème, car il
printf %d
devrait fonctionner avec des valeurs non entières. Cela ne fonctionnera pas non plus avec des flottants (sauf si vous modifiez le spécificateur de format en%f
, où vous rencontrerez des problèmes d'arrondi).test $1 -gt $2
vous indiquera si la comparaison a échoué ou non (l'état de sortie de 2 signifie qu'il y a eu une erreur pendant le test. Comme il s'agit généralement d'un shell intégré, aucun processus supplémentaire n'est généré - nous parlons d'un ordre de centaines exécution plus rapide. Ne fonctionne que sur les entiers.Si vous avez besoin de comparer quelques nombres à virgule flottante, une option intéressante pourrait être
bc
:serait l'équivalent de
test $1 -gt $2
, et en utilisant dans shell:est toujours presque 2,5 fois plus rapide que
printf | sort | head
(pour deux nombres).Si vous pouvez compter sur les extensions GNU
bc
, vous pouvez également utiliser laread()
fonction pour lire les numéros directement dans lebc
script.la source
dc -e "${max}sm[z0=?dlm<Mps0lTx]ST[?z0!=Tq]S?[s0lm]SMlTx"
- oh, sauf que çadc
fait tout (sauf l’écho, même s’il le pourrait) - il lit stdin et affiche soit$max
le numéro d’entrée en fonction de est plus petit. Quoi qu'il en soit, je ne tiens pas vraiment à l'expliquer et votre réponse est meilleure que ce que j'allais écrire. Alors, ayez mon vote positif, s'il vous plaît.dc
script expliqué serait vraiment bien, RPN n'est pas vu aussi souvent ces jours-ci.dc
je peux faire l’E / S seul, ce sera encore plus élégant que.Pour obtenir la plus grande valeur de $ a et $ b, utilisez ceci:
Mais vous avez besoin de quelque chose autour de ça, vous ne voulez probablement pas exécuter le nombre, donc pour afficher la plus grande valeur des deux, utilisez "echo"
Ce qui précède s’intègre parfaitement dans une fonction shell, par exemple
Pour assigner le plus grand des deux à la variable, utilisez cette version modifiée:
ou utilisez la fonction définie:
La variante de fonction vous donne également la possibilité d’ajouter une vérification nette des erreurs d’entrée.
Pour renvoyer le maximum de deux nombres décimaux / flottants que vous pouvez utiliser
awk
EDIT: En utilisant cette technique, vous pouvez créer une fonction "limite" qui opère dans le sens contraire de votre édition / note. Cette fonction retournera le plus bas des deux, par exemple:
J'aime mettre les fonctions utilitaires dans un fichier séparé, appelez-le
myprogram.funcs
et utilisez-le dans un script comme suit:FWIW fait toujours ce que vous avez fait et votre version, même si elle est plus détaillée, est tout aussi efficace.
La forme la plus compacte n’est pas vraiment meilleure, mais évite d’encombrer vos scripts. Si vous avez plusieurs constructions simples if-then-else-fi, le script se développe rapidement.
Si vous souhaitez réutiliser plusieurs fois la recherche de nombres plus grands / plus petits dans un même script, placez-la dans une fonction. Le format de la fonction facilite le débogage et la réutilisation et vous permet de remplacer facilement cette partie du script, par exemple avec une commande awk pour pouvoir traiter des nombres décimaux non entiers.
S'il s'agit d'un cas d'utilisation unique, codez-le simplement en ligne.
la source
Vous pouvez définir une fonction comme
Appelez comme
maxnum 54 42
et ça résonne54
. Vous pouvez ajouter des informations de validation dans la fonction (telles que deux arguments ou des nombres comme arguments) si vous le souhaitez.la source
function maxnum {
enmaxnum() {
et ça fonctionnera pour beaucoup plus de coquillages.A partir d'un script shell, il existe un moyen d'utiliser n'importe quelle méthode statique publique Java (et par exemple Math.min () ). De bash sur Linux:
Cela nécessite Java Shell Bridge https://sourceforge.net/projects/jsbridge/
Très rapide, car les appels de méthode sont acheminés en interne ; aucun processus requis.
la source
La plupart des gens feraient juste
sort -n input | head -n1
(ou la queue), c'est assez bon pour la plupart des situations de script. Cependant, c'est un peu maladroit si vous avez des chiffres dans une ligne plutôt que dans une colonne - vous devez l'imprimer dans un format approprié (tr ' ' '\n'
ou quelque chose de similaire).Les coques ne sont pas tout à fait idéales pour le traitement numérique, mais vous pouvez facilement vous connecter à un autre programme plus performant. En fonction de vos préférences, vous pouvez téléphoner au maximum
dc
(un peu brouillé, mais si vous savez ce que vous faites, tout va bien - voir la réponse de mikeserv), ouawk 'NR==1{max=$1} {if($1>max){max=$1}} END { print max }'
. Ou éventuellementperl
oupython
si vous préférez. Une solution (si vous êtes prêt à installer et à utiliser un logiciel moins connu) seraitised
(surtout si vos données sont sur une seule ligne: il vous suffit de le faireised --l input.dat 'max$1'
).Parce que vous demandez deux chiffres, tout cela est excessif. Cela devrait suffire:
la source
sys.argv
:python2 -c 'import sys; print (max(sys.argv))' "$@"
sort + head
sont excessifs maispython
ne sont pas calculés.python
parce qu'il est ordonné.python
bigot (ou parce qu'elle ne nécessite ni fourchette ni interpréteur gigantesque supplémentaire) . Ou peut-être les deux.