¿Hay alguna manera de comparar tales cadenas en bash, por ejemplo: 2.4.5y 2.8y 2.4.5.1?
linux
bash
versioning
exabiche
fuente
fuente

bc. Es texto, no números.2.1 < 2.10Fallarí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
sortcomando debería tener una-Vopció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.sortno tiene-Vopción.printflugar deecho -e.sorttambién tiene-Co--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$?es0verdadero si puede usarlo directamente después de laifdeclaración.GNU sort tiene una opción para ello:
da:
fuente
echo -e "2.4.10\n2.4.9" | sort -n -t.sortno tiene-Vopció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
-topción solo acepta pestañas de un solo carácter ... de lo contrario,2.4-r9también funcionaría. Qué pena: /-ga-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 -ntrabajar, tuve que cambiarme atr '.' '\n'trSalida 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-sortcambia 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..0fallas 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.5b1.6 > 1.5bif 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 deayb, 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
aybdejar solo la secuencia de elementos numéricos como variables localesaiybi, 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 paraaiybi. Comience manteniendo solo los puntos entre elementos, cuyo número es igual al número de elementos deaybrespectivamente.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.$bcon%${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 paraprintfdividir en elementos individuales.Con los primeros
printfelementos dease rellenan a la izquierda con espacios, mientras que se añaden suficientes elementos "0"bppara garantizar que la cadena resultantease pueda comparar significativamente con un formato similarb.Nótese que se anexe
bp- noapaaicausaapybppuede tener diferentes longitudes, por lo que este resultado enaybtener la misma longitud.Con el segundo
printfañadimos la parte cartaalaacon suficiente relleno para permitir una comparación significativa. Ahoraaestá 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=bLínea 17 : Prueba para operadores de comparación incorporados.
<>
fuente
Estoy usando Linux incrustado (Yocto) con BusyBox. BusyBox
sortno tiene una-Vopción (pero BusyBoxexpr matchpuede 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
10lo 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-r3versus1.2-r41.2rc3versus1.2r4Tenga 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 -CEsta también es una
pure bashsolució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.3Aquí 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 1sino en suecholugar; (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