Comment comparer deux chaînes de caractères en dot séparés format de version de Bash?
Est-il possible de comparer ces chaînes sur bash, par exemple: 2.4.5
et 2.8
et 2.4.5.1
?
- Non, ne pas le faire avec des
bc
. C'est un texte pas des numéros.2.1 < 2.10
serait un échec de cette façon.
Vous devez vous connecter pour publier un commentaire.
Ici est un pur Bash version qui ne nécessite pas d'utilitaires externes:
Exécuter les tests:
1.0 > 1
au lieu d'être égal.return 2
avecif (( ${#ver1[@]} < ${#ver2[@]} )); then return 2; else return 0; fi
?1.0 = 1
il est donc compatible avec1.01.1 = 1.1.1
.local IFS=.
suivie parver1=($1) ver2=($2)
, et laisser ainsi bash faire tout le travail de la séparation de tous les sous-numéros de version. J'aurais probablement juste aveuglément chargé et a commencé à marteler un tas desed
etawk
commandes de diviser les sortir. C'est toujours agréable d'apprendre de nouvelles façons de penser plus intelligent sur les choses. Après tout, le but principal de 99% de mes scripts est de gagner du temps en automatisant les tâches fastidieuses et répétitives. Merci.Please don't use it for software or documentation, since it is incompatible with the GNU GPL
:/ mais +1 pour le code10#0 1 > 10#0: syntax error in expression (error token is "1 > 10#0") 10#0 1 < 10#0: syntax error in expression (error token is "1 < 10#0")
versionGNU bash, version 3.2.51(1)-release (x86_64-apple-darwin13)
0.2
), et en citant les variables d'entrée de mal (je n'aivercomp "$1 $2"
au lieu devercomp "$1" "$2"
ou tout simplementvercomp $1 $2
)2.4-r9
etr.4-r10
.if [[ $2 == '!=' ]] ; then if [[ $op != '=' ]] ; then # True return 0 fi # False return 1 fi
$2
ne pourra jamais égaler!=
.Si vous avez coreutils-7 (dans Ubuntu Karmic mais pas Jaunty) puis votre
sort
commande doit avoir un-V
option (version sorte que vous pouvez utiliser pour faire la comparaison:brew install coreutils
. Ensuite, le dessus doit juste être modifié pour utiliser gsort.sort
n'a pas-V
option.filevercmp
degnulib
. Fait intéressant, pas lastrverscmp
de glibc: stackoverflow.com/a/37015135/895245printf
au lieu deecho -e
.2
et2.0
).verlte 2 2.0
réussit, tout enverlte 2.0 2
ne parvient pas, pour les raisons que vous décrivez (2
vient toujours avant2.0
). Je m'attends à ce qu'elles produisent le même résultat.~
de soutien. En RPM et deb emballage,~
trie avant de n'importe quel caractère, y compris le vide. I. e.,2.0~beta1 < 2.0
.sort -V
prend en charge cette conventionsort
a également-C
ou--check=silent
, de sorte que vous pouvez écrireverlte() { printf '%s\n%s' "$1" "$2" | sort -C -V }
; et la vérification stricte moins que ce n'est plus simplement le fait queverlt() { ! verlte "$2" "$1" }
.Il n'y a probablement pas universellement bonne façon d'y parvenir. Si vous essayez de comparer les versions dans le système de paquets Debian essayer
dpkg --compare-versions <first> <relation> <second>.
dpkg --compare-versions "1.0" "lt" "1.2"
signifie 1.0 moins de 1.2. Le résultat de la comparaison$?
est0
si vrai, alors vous pouvez l'utiliser directement aprèsif
déclaration.GNU tri a une option pour elle:
donne:
echo -e "2.4.10\n2.4.9" | sort -n -t.
sort
n'a pas-V
option.printf '%s\n' "2.4.5" "2.8" "2.4.5.1" | sort -V
.coreutils 7+
.Bien si vous savez le nombre de champs que vous pouvez utiliser -k n,n et obtenir un super-simple solution
2.4-r9
etr.4-r10
.-t
option accepte uniquement à caractère unique onglets...sinon,2.4-r9
marcherait aussi bien. Ce qui est bien dommage :/-g
à-n
. Aucune raison de ne pas pour cet exemple? Sur une note... pour effectuer un "plus grand que" type de comparaison, vous pouvez vérifier si le tri souhaité est le même que le tri... par exempledesired="1.9\n1.11"; actual="$(echo -e $desired |sort -t '.' -k 1,1 -k 2,2 -g)";
puis vérifiezif [ "$desired" = "$actual" ]
.C'est plus de 4 champs dans la version.
printf "%03d%03d%03d%03d" $(echo "$1" | tr '.' '\n' | head -n 4)
head -n
de travail, j'ai dû changer detr '.' '\n'
tr -cs '0-9' ' '
pour nettoyer et séparer les traits d'union, des virgules, et d'autres délimiteurs.tr
de sortie à travers lased 's/\(^\| \)0\([0-9][0-9]*\)/\1\2/g'
qui prendra soin de cela (Assez maladroitement)awk
à la place.ver () { echo "$@" | awk -F. '{ printf("%d%03d%03d", $1,$2,$3); }'; }
Il a parfaitement fonctionné pour mes besoinsUtilisé en tant que tel:
(à partir de https://apple.stackexchange.com/a/123408/11374)
Vous pouvez récursive split sur
.
et de comparer, comme indiqué dans l'algorithme suivant, pris de ici. Il renvoie 10 si les versions sont les mêmes, 11 si la version 1 est supérieure à la version 2 et 9 de l'autre.Source
J'utilise Linux embarqué (Yocto) avec BusyBox. BusyBox
sort
n'ont pas de-V
option (mais BusyBoxexpr match
peut faire des expressions régulières). J'ai donc besoin d'un Bash version de comparer qui a travaillé avec cette contrainte.J'ai fait la suite (similaire à Dennis Williamson réponse) à comparer à l'aide d'un "naturel tri" type d'algorithme. Il coupe la corde dans les parties numériques et non-numériques parties; il compare le numérique parties numériquement (donc
10
est plus grand que9
), et compare le non-numérique de pièces comme une simple comparaison ASCII.Il peut comparer plus compliqué que la version des nombres tels que
1.2-r3
contre1.2-r4
1.2rc3
contre1.2r4
Noter qu'il ne retourne pas le même résultat pour certains d'angle cas dans Dennis Williamson réponse. En particulier:
Mais ce sont des cas limites, et je pense que les résultats sont encore raisonnables.
si c'est juste sur le point de savoir si une version est inférieure à une autre, je suis venu vérifier si
sort --version-sort
de modifier l'ordre de mes chaînes de version:J'ai implémenté une fonction qui renvoie les mêmes résultats que Dennis Williamson, mais utilise moins de lignes. Il effectue un test de cohérence initialement, ce qui provoque
1..0
à l'échec de ses tests (dont je dirais devrait être le cas), mais tous ses autres tests passent avec ce code:seq
commandeIci est une simple Bash fonction qui n'utilise pas les commandes externes. Il fonctionne pour la version chaînes qui ont jusqu'à trois les parties numériques en eux - moins de 3 est très bien. Il peut facilement être étendu pour plus. Elle met en œuvre
=
,<
,<=
,>
,>=
, et!=
conditions.Voici le test:
Un sous-ensemble de la sortie du test:
--check=silent
, sans avoir besoin detest
, comme ceci:if printf '%s\n%s' 4.2.0 "$OVFTOOL_VERSION" | sort --version-sort -C
V
- pur bash solution, pas de utilitaires externes requis.=
==
!=
<
<=
>
et>=
(lexicographique).1.5a < 1.5b
1.6 > 1.5b
if V 1.5 '<' 1.6; then ...
.<>
<>
Code Expliqué
Ligne 1: Définir des variables locales:
a
,op
,b
- comparaison des opérandes et l'opérateur, c'est à dire, "3.6" > "3.5" une.al
,bl
- lettre de queues dea
etb
, initialisé à la queue de l'élément, c'est à dire, "6" et "5a".Les lignes 2, 3: à Gauche-garniture chiffres de la queue, des articles ainsi que des lettres sont de gauche, le cas échéant, c'est à dire, "" et "un".
Ligne 4: Droit de la garniture de lettres de
a
etb
quitter la séquence numérique des éléments comme des variables localesai
etbi
, c'est à dire, "3.6" et "3.5".Exemple Notable: "4.01-RC2" > "4.01-RC1" les rendements de l'ia="4.01" al="-RC2" et bi="4.01" bl="-RC1".
Ligne 6: Définir des variables locales:
ap
,bp
- de zéro à droite-rembourrages pourai
etbi
. Commencez par garder l'inter-élément de points, dont le nombre est égal au nombre d'éléments dea
etb
respectivement.Ligne 7: Puis ajouter "0" après chaque point de faire de rembourrage masques.
Ligne 9: variables Locales:
w
- largeur de l'objetfmt
- format de printf, pour être calculéx
- temporaireIFS=.
bash divise les valeurs de la variable à '.'.Ligne 10: Calculer
w
, le maximum de la largeur de l'objet, qui sera utilisé pour aligner les éléments de comparaison lexicographique. Dans notre exemple, w=2.Ligne 11: Créer le printf alignement format en remplaçant chaque caractère de
$a.$b
avec%${w}s
, c'est à dire, "3.6" > "3.5 un" produit "%2s%2s%2s%2s".Ligne 12: "printf v un" définit la valeur de la variable
a
. C'est l'équivalent dea=sprintf(...)
dans de nombreux langages de programmation. Soulignons ici que, par l'effet de la FI=. les arguments deprintf
divisé en éléments individuels.Avec la première
printf
éléments dea
sont à gauche-collier avec des espaces tout assez "0" des éléments sont ajoutés à la fin debp
pour s'assurer que la chaîne résultantea
peuvent être utilement comparé à un formatées de la même manièreb
.Noter que nous append
bp
- pasap
àai
parce queap
etbp
peuvent avoir des durées différentes, de sorte que cette résultats dansa
etb
ayant des longueurs égales.Avec la deuxième
printf
on ajoute la lettre partieal
àa
avec rembourrage suffisant pour permettre une comparaison significative. Maintenanta
est prêt pour la comparaison avecb
.Ligne 13: la Même que pour la ligne 12, mais pour
b
.Ligne 15: Split comparaison entre non-intégré (
<=
et>=
) et intégré dans les opérateurs.Ligne 16: Si l'opérateur de comparaison est
<=
puis testez poura<b or a=b
- respectivement>=
a<b or a=b
Ligne 17: Test intégré des opérateurs de comparaison.
<>
Pour l'ancienne version/busybox
sort
. La forme Simple de fournir à peu près résultat et fonctionne souvent.C'est escpecial utiles sur la version qui contient de l'alpha des symboles comme
2.4-r9
etr.4-r10
.Voici un autre pur bash solution sans appels externes:
Et il est encore plus simple solution, si vous êtes sûr que les versions en question ne contiennent pas de zéros après le premier point:
Cela fonctionne pour quelque chose comme 1.2.3 vs 1.3.1 vs 0.9.7, mais ne fonctionne pas avec
1.2.3 vs 1.2.3.0 ou 1.01.1 vs 1.1.1
4.4.4 > 44.3
Voici un raffinement de la réponse sommet (Dennis) qui est plus concis et utilise une autre valeur de retour de régime pour le rendre facile à mettre en œuvre <= et >= avec une seule comparaison. Il compare également tout ce qui est après le premier caractère qui n'est pas dans [0-9.] lexicographiquement, donc 1.0rc1 < 1.0rc2.
J'ai mis en place encore un autre comparateur de fonction. Celui-ci avait deux exigences: (i) je ne voulais pas la fonction pour échouer en utilisant
return 1
maisecho
à la place; (ii) que nous récupérons des versions à partir d'un dépôt git version "1.0" doit être plus grand que "1.0.2", ce qui signifie que "1.0" vient de tronc.N'hésitez pas à commenter et suggérer des améliorations.
Vous pouvez utiliser version de la CLI pour vérifier la version de contraintes
Script Bash exemple:
Je suis venu à travers et résolu ce problème, ajouter un autre (et plus court et plus simple) de réponse...
Première note, étendu shell comparaison a échoué comme vous le savez peut-être déjà...
À l'aide de la tri -t'.'-g (ou tri -V tel que mentionné par kanaka) pour commander des versions et bash simple comparaison de chaînes de caractères, j'ai trouvé une solution. Le fichier d'entrée contient des versions dans les colonnes 3 et 4 qui je veux comparer. Ce parcourt la liste de l'identification d'un match, ou si l'un est plus grand que l'autre. Espérons que cela peut toujours aider ceux qui cherchent à le faire à l'aide de bash aussi simple que possible.
Grâce à Barry blog pour le genre d'idée...
ref: http://bkhome.org/blog/?viewDetailed=02199
Il est assez simple et de petite taille.
echo -ne "$1\n$2"
avecprintf '%s\n ' "$1" "$2"
. Aussi, il est préférable d'utiliser$()
au lieu de la backtics.Comment à ce sujet? Semble fonctionner?
Merci à Dennis de la solution, nous pouvons l'étendre à permettre à des opérateurs de comparaison " >', '<', '=', '==', '<=', et '>='.
Nous pouvons alors utiliser des opérateurs de comparaison dans des expressions comme:
et de tester seulement le vrai/faux de la raison, comme:
Voici un autre pur bash version, nettement plus petite que la accepté de répondre. Il vérifie uniquement si une version est inférieure ou égale à une "version", et il va vérifier alphanumérique séquences de manière lexicographique, qui donne souvent de mauvais résultat ("snapshot" n'est pas plus tard que la "libération", pour donner un exemple courant). Il fonctionne parfaitement pour la majeur/mineur.
Une autre approche(version modifiée de @joynes) qui compare les pointillés versions comme demandé dans la question
(j'.e "1.2", "2.3.4", "1.0", "1.10.1", etc.).
Le nombre maximum de positions doit être connu à l'avance. L'approche prévoit max la version 3 positions.
exemple d'utilisation:
retourne: 1 depuis 1.10.1 est plus que de 1,7
retourne: 0 depuis 1.10.1 est inférieur 1.11
Ici est un pur Bash solution qui prend en charge les révisions (par exemple, '1.0-r1'), basé sur la réponse postée par Dennis Williamson. Il peut facilement être modifié pour prendre en charge des trucs comme "- RC1 " ou de l'extrait de la version à partir d'une chaîne plus complexes, par modification de l'expression régulière.
Pour plus de détails concernant la mise en œuvre, veuillez vous référer aux commentaires de code et/ou activer le inclus le code de débogage:
C'est aussi un
pure bash
solution, comme printf est un bash builtin.