¿Hay alguna manera de comparar tales cadenas en bash, por ejemplo: 2.4.5
y 2.8
y 2.4.5.1
?
linux
bash
versioning
exabiche
fuente
fuente
bc
. Es texto, no números.2.1 < 2.10
Fallaría de esta manera.Respuestas:
Aquí hay una versión pura de Bash que no requiere ninguna utilidad externa:
Ejecute las pruebas:
fuente
Please don't use it for software or documentation, since it is incompatible with the GNU GPL
: / but +1 para un gran códigoSi tiene coreutils-7 (en Ubuntu Karmic pero no Jaunty), entonces su
sort
comando debería tener una-V
opción (clasificación de versión) que podría usar para hacer la comparación:fuente
brew install coreutils
. Entonces lo anterior solo debe modificarse para usar gsort.sort
no tiene-V
opción.printf
lugar deecho -e
.sort
también tiene-C
o--check=silent
, para que puedas escribirverlte() { printf '%s\n%s' "$1" "$2" | sort -C -V }
; y comprobar estrictamente menos de lo que se hace simplemente comoverlt() { ! verlte "$2" "$1" }
.Probablemente no haya una forma universalmente correcta de lograr esto. Si está intentando comparar versiones en el sistema de paquetes de Debian, intente
dpkg --compare-versions <first> <relation> <second>.
fuente
dpkg --compare-versions "1.0" "lt" "1.2"
significa 1.0 menos que 1.2. El resultado de la comparación$?
es0
verdadero si puede usarlo directamente después de laif
declaración.GNU sort tiene una opción para ello:
da:
fuente
echo -e "2.4.10\n2.4.9" | sort -n -t.
sort
no tiene-V
opción.printf '%s\n' "2.4.5" "2.8" "2.4.5.1" | sort -V
.coreutils 7+
.Bueno, si conoce la cantidad de campos, puede usar -kn, ny obtener una solución súper simple
fuente
-t
opción solo acepta pestañas de un solo carácter ... de lo contrario,2.4-r9
también funcionaría. Qué pena: /-g
a-n
. ¿Alguna razón por la que no para este ejemplo? En una nota al margen ... para realizar una comparación de tipo "mayor que", puede verificar si el orden deseado es el mismo que el orden real ... por ejemplo,desired="1.9\n1.11"; actual="$(echo -e $desired |sort -t '.' -k 1,1 -k 2,2 -g)";
y luego verificarif [ "$desired" = "$actual" ]
.Esto es para un máximo de 4 campos en la versión.
fuente
printf "%03d%03d%03d%03d" $(echo "$1" | tr '.' '\n' | head -n 4)
head -n
trabajar, tuve que cambiarme atr '.' '\n'
tr
Salida de tubería a través de lased 's/\(^\| \)0\([0-9][0-9]*\)/\1\2/g'
cual se encargará de eso (bastante torpemente)Usado como tal:
(de https://apple.stackexchange.com/a/123408/11374 )
fuente
Puede dividir
.
y comparar recursivamente como se muestra en el siguiente algoritmo, tomado de aquí . Devuelve 10 si las versiones son las mismas, 11 si la versión 1 es mayor que la versión 2 y 9 en caso contrario.Fuente
fuente
si se trata de saber si una versión es inferior a otra, se me ocurrió comprobar si
sort --version-sort
cambia el orden de las cadenas de mi versión:fuente
Implementé una función que devuelve los mismos resultados que Dennis Williamson pero usa menos líneas. Inicialmente, realiza una verificación de cordura que causa
1..0
fallas en sus pruebas (lo que diría que debería ser el caso), pero todas sus otras pruebas pasan con este código:fuente
Aquí hay una función Bash simple que no utiliza comandos externos. Funciona para cadenas de versión que tienen hasta tres partes numéricas en ellas; menos de 3 también está bien. Se puede extender fácilmente por más. Implementa
=
,<
,<=
,>
,>=
, y!=
condiciones.Aquí está la prueba:
Un subconjunto de la salida de prueba:
fuente
V
: solución de bash puro, no se requieren utilidades externas.=
==
!=
<
<=
>
y>=
(lexicográficos).1.5a < 1.5b
1.6 > 1.5b
if V 1.5 '<' 1.6; then ...
.<>
<>
Código explicado
Línea 1 : Definir variables locales:
a
,op
,b
- operandos de comparación y operador, es decir, "3.6"> "3.5a".al
,bl
- colas de letras dea
yb
, inicializadas al elemento de cola, es decir, "6" y "5a".Líneas 2, 3 : dígitos de recorte a la izquierda de los elementos de la cola, por lo que solo quedan letras, si las hay, es decir, "" y "a".
Línea 4 : Recortar letras a la derecha de
a
yb
dejar solo la secuencia de elementos numéricos como variables localesai
ybi
, es decir, "3.6" y "3.5". Ejemplo notable: "4.01-RC2"> "4.01-RC1" produce ai = "4.01" al = "- RC2" y bi = "4.01" bl = "- RC1".Línea 6 : Definir variables locales:
ap
,bp
- cero rellenos a la derecha paraai
ybi
. Comience manteniendo solo los puntos entre elementos, cuyo número es igual al número de elementos dea
yb
respectivamente.Línea 7 : luego agregue "0" después de cada punto para hacer máscaras de relleno.
Línea 9 : Variables locales:
w
- ancho del artículofmt
- cadena de formato printf, que se calcularáx
- temporalIFS=.
bash divide valores variables en '.'.Línea 10 : Calcular
w
, el ancho máximo del elemento, que se utilizará para alinear los elementos para la comparación lexicográfica. En nuestro ejemplo w = 2.Línea 11 : Cree el formato de alineación printf reemplazando cada carácter de
$a.$b
con%${w}s
, es decir, "3.6"> "3.5a" produce "% 2s% 2s% 2s% 2s".Línea 12 : "printf -v a" establece el valor de la variable
a
. Esto es equivalente aa=sprintf(...)
en muchos lenguajes de programación. Tenga en cuenta que aquí, por efecto de IFS =. Los argumentos paraprintf
dividir en elementos individuales.Con los primeros
printf
elementos dea
se rellenan a la izquierda con espacios, mientras que se añaden suficientes elementos "0"bp
para garantizar que la cadena resultantea
se pueda comparar significativamente con un formato similarb
.Nótese que se anexe
bp
- noap
aai
causaap
ybp
puede tener diferentes longitudes, por lo que este resultado ena
yb
tener la misma longitud.Con el segundo
printf
añadimos la parte cartaal
aa
con suficiente relleno para permitir una comparación significativa. Ahoraa
está listo para comparar conb
.Línea 13 : igual que la línea 12 pero para
b
.Línea 15 : Divida los casos de comparación entre operadores no integrados (
<=
y>=
) y operadores integrados.Línea 16 : Si el operador de comparación se
<=
pruebaa<b or a=b
, respectivamente>=
a<b or a=b
Línea 17 : Prueba para operadores de comparación incorporados.
<>
fuente
Estoy usando Linux incrustado (Yocto) con BusyBox. BusyBox
sort
no tiene una-V
opción (pero BusyBoxexpr match
puede hacer expresiones regulares). Así que necesitaba una comparación de la versión Bash que funcionara con esa restricción.He hecho lo siguiente (similar a la respuesta de Dennis Williamson ) para comparar usando un tipo de algoritmo de "clasificación natural". Divide la cadena en partes numéricas y partes no numéricas; compara las partes numéricas numéricamente (por
10
lo tanto es mayor que9
) y compara las partes no numéricas como una comparación ASCII simple.Puede comparar números de versión más complicados como
1.2-r3
versus1.2-r4
1.2rc3
versus1.2r4
Tenga en cuenta que no devuelve el mismo resultado para algunos de los casos de esquina en la respuesta de Dennis Williamson . En particular:
Pero esos son casos de esquina, y creo que los resultados siguen siendo razonables.
fuente
fuente
--check=silent
, sin necesidad detest
, de esta manera:if printf '%s\n%s' 4.2.0 "$OVFTOOL_VERSION" | sort --version-sort -C
Esta también es una
pure bash
solución, ya que printf es un bash incorporado.fuente
Para la versión anterior / busybox
sort
. La forma simple proporciona un resultado aproximado y, a menudo, funciona.Esto es especialmente útil en la versión que contiene símbolos alfa como
fuente
¿Qué tal esto? ¿Parece funcionar?
fuente
Aquí hay otra solución bash pura sin llamadas externas:
Y hay una solución aún más simple, si está seguro de que las versiones en cuestión no contienen ceros a la izquierda después del primer punto:
Esto funcionará para algo como 1.2.3 vs 1.3.1 vs 0.9.7, pero no funcionará con 1.2.3 vs 1.2.3.0 o 1.01.1 vs 1.1.1
fuente
4.4.4 > 44.3
Aquí hay un refinamiento de la respuesta superior (Dennis) que es más conciso y utiliza un esquema de valor de retorno diferente para facilitar la implementación de <= y> = con una sola comparación. También compara todo después del primer carácter que no está en [0-9.] Lexicográficamente, por lo que 1.0rc1 <1.0rc2.
fuente
Implementé otra función de comparación. Este tenía dos requisitos específicos: (i) no quería que la función fallara usando
return 1
sino en suecho
lugar; (ii) ya que estamos recuperando versiones de un repositorio de git, la versión "1.0" debería ser mayor que "1.0.2", lo que significa que "1.0" proviene de troncal.Siéntase libre de comentar y sugerir mejoras.
fuente
Puede usar la versión CLI para verificar las restricciones de la versión
Ejemplo de script Bash:
fuente
Encontré y resolví este problema, para agregar una respuesta adicional (y más corta y más simple) ...
Primera nota, la comparación de shell extendida falló como ya puede saber ...
Usando el sort -t '.'- g (o sort -V como lo menciona kanaka) para ordenar versiones y una simple comparación de cadenas de bash, encontré una solución. El archivo de entrada contiene versiones en las columnas 3 y 4 que quiero comparar. Esto itera a través de la lista que identifica una coincidencia o si una es mayor que la otra. Espero que esto pueda ayudar a cualquiera que quiera hacer esto usando bash lo más simple posible.
Gracias al blog de Barry por la idea de clasificación ... ref: http://bkhome.org/blog/?viewDetailed=02199
fuente
Es bastante simple y pequeño.
fuente
echo -ne "$1\n$2"
porprintf '%s\n ' "$1" "$2"
. También es mejor usar en$()
lugar de los backtics.Gracias a la solución de Dennis, podemos extenderla para permitir operadores de comparación '>', '<', '=', '==', '<=' y '> ='.
Entonces podemos usar operadores de comparación en expresiones como:
y pruebe solo el verdadero / falso del resultado, como:
fuente
Aquí hay otra versión de bash puro, bastante más pequeña que la respuesta aceptada. Solo verifica si una versión es menor o igual que una "versión mínima", y verificará las secuencias alfanuméricas lexicográficamente, lo que a menudo da un resultado incorrecto ("instantánea" no es posterior a "release", para dar un ejemplo común) . Funcionará bien para mayor / menor.
fuente
Otro enfoque (versión modificada de @joynes) que compara versiones punteadas como se hizo en la pregunta
(es decir, "1.2", "2.3.4", "1.0", "1.10.1", etc.).
El número máximo de puestos debe conocerse de antemano. El enfoque espera un máximo de 3 posiciones de versión.
ejemplo de uso:
devuelve: 1 desde 1.10.1 es mayor que 1.7
devuelve: 0 ya que 1.10.1 es menor que 1.11
fuente
Aquí hay una solución Bash pura que admite revisiones (por ejemplo, '1.0-r1'), basada en la respuesta publicada por Dennis Williamson . Se puede modificar fácilmente para admitir cosas como '-RC1' o extraer la versión de una cadena más compleja cambiando la expresión regular.
Para obtener detalles sobre la implementación, consulte los comentarios en código y / o habilite el código de depuración incluido:
fuente
Wow ... esto está muy por debajo de la lista de una vieja pregunta, pero creo que esta es una respuesta bastante elegante. Primero convierta cada versión separada por puntos en su propia matriz, usando la expansión de parámetros de shell (Ver Expansión de parámetros de Shell ).
Ahora las dos matrices tienen el número de versión como una cadena numérica en orden de prioridad. Muchas de las soluciones anteriores lo llevan desde allí, pero todo deriva de la observación de que la cadena de versión es solo un número entero con una base arbitraria. Podemos probar encontrar el primer dígito desigual (como lo hace strcmp para los caracteres en una cadena).
Esto hace eco de un número negativo si la primera versión es menor que la segunda, un cero si son iguales y un número positivo si la primera versión es mayor. Alguna salida:
Casos degenerados como ".2" o "3.0". no funciona (resultados indefinidos), y si hay caracteres no numéricos junto al '.' puede fallar (no se ha probado) pero ciertamente será indefinido. Por lo tanto, esto debe combinarse con una función de desinfección o una verificación adecuada para un formato válido. Además, estoy seguro de que con algunos ajustes, esto podría hacerse más robusto sin demasiado equipaje adicional.
fuente
El crédito va a @Shellman
fuente