Existe alguma maneira de comparar essas strings no bash, por exemplo: 2.4.5
e 2.8
e 2.4.5.1
?
linux
bash
versioning
exabiche
fonte
fonte
bc
. É texto, não números.2.1 < 2.10
falharia assim.Respostas:
Aqui está uma versão pura do Bash que não requer nenhum utilitário externo:
Execute os testes:
fonte
Please don't use it for software or documentation, since it is incompatible with the GNU GPL
: / mas +1 para obter um ótimo códigoSe você possui o coreutils-7 (no Ubuntu Karmic, mas não o Jaunty), seu
sort
comando deve ter uma-V
opção (tipo de versão) que você pode usar para fazer a comparação:fonte
brew install coreutils
. Em seguida, o acima deve ser modificado para usar o gsort.sort
não tem-V
opção.printf
vez deecho -e
.sort
também possui-C
ou--check=silent
, para que você possa escreververlte() { printf '%s\n%s' "$1" "$2" | sort -C -V }
; e checando estritamente menos do que simplesmente é feitoverlt() { ! verlte "$2" "$1" }
.Provavelmente não existe uma maneira universalmente correta de conseguir isso. Se você está tentando comparar versões no sistema de pacotes Debian, tente
dpkg --compare-versions <first> <relation> <second>.
fonte
dpkg --compare-versions "1.0" "lt" "1.2"
significa 1,0 menor que 1,2. O resultado da comparação$?
é0
verdadeiro, para que você possa usá-lo diretamente após aif
declaração.A classificação GNU tem uma opção para isso:
dá:
fonte
echo -e "2.4.10\n2.4.9" | sort -n -t.
sort
não tem-V
opção.printf '%s\n' "2.4.5" "2.8" "2.4.5.1" | sort -V
.coreutils 7+
.Bem, se você souber o número de campos, poderá usar -kn, n e obter uma solução super-simples
fonte
-t
opção aceita apenas guias de caracteres únicos ... caso contrário,2.4-r9
também funcionaria. Que pena: /-g
para-n
. Alguma razão para não fazer este exemplo? Em uma nota lateral ... para executar uma comparação do tipo "maior que", você pode verificar se a classificação desejada é igual à classificação real ... por exemplo,desired="1.9\n1.11"; actual="$(echo -e $desired |sort -t '.' -k 1,1 -k 2,2 -g)";
e depois verificarif [ "$desired" = "$actual" ]
.Isso é para no máximo 4 campos na versão.
fonte
printf "%03d%03d%03d%03d" $(echo "$1" | tr '.' '\n' | head -n 4)
head -n
trabalhar, eu tive que mudar paratr '.' '\n'
tr
de saída através dased 's/\(^\| \)0\([0-9][0-9]*\)/\1\2/g'
qual irá tomar o cuidado de que (Em vez desajeitada)Usado como tal:
(de https://apple.stackexchange.com/a/123408/11374 )
fonte
Você pode dividir
.
e comparar recursivamente, conforme mostrado no algoritmo a seguir, extraído daqui . Retorna 10 se as versões forem iguais, 11 se a versão 1 for maior que a versão 2 e 9, caso contrário.Fonte
fonte
se ele está prestes a saber se uma versão é menor que a outra, cheguei a verificar se
sort --version-sort
a ordem das minhas strings de versão é alterada:fonte
Eu implementei uma função que retorna os mesmos resultados que os de Dennis Williamson, mas usa menos linhas. Realiza uma verificação de integridade inicialmente que causa
1..0
falhas nos testes (o que eu diria que deveria ser o caso), mas todos os outros testes passam com este código:fonte
Aqui está uma função Bash simples que não usa comandos externos. Ele funciona para strings de versão que têm até três partes numéricas - menos de 3 também é bom. Pode ser facilmente estendido para mais. Ele implementa
=
,<
,<=
,>
,>=
, e!=
condições.Aqui está o teste:
Um subconjunto da saída de teste:
fonte
V
- solução bash pura, sem necessidade de utilitários externos.=
==
!=
<
<=
>
e>=
(lexicográfico).1.5a < 1.5b
1.6 > 1.5b
if V 1.5 '<' 1.6; then ...
.<>
<>
Código explicado
Linha 1 : Defina variáveis locais:
a
,op
,b
- operandos de comparação e operador, ou seja, "3.6"> "3.5a".al
,bl
- caudas das letrasa
eb
inicializadas no item final, ou seja, "6" e "5a".Linhas 2, 3 : dígitos à esquerda dos itens da cauda, para que apenas as letras sejam deixadas, se houver, ou seja, "" e "a".
Linha 4 : Aparar letras à direita de
a
eb
para deixar apenas a sequência de itens numéricos como variáveis locaisai
ebi
, por exemplo, "3.6" e "3.5". Exemplo notável: "4.01-RC2"> "4.01-RC1" gera ai = "4.01" al = "- RC2" e bi = "4.01" bl = "- RC1".Linha 6 : Defina variáveis locais:
ap
,bp
- zero remada à direita paraai
ebi
. Comece mantendo apenas os pontos entre itens, cujo número é igual ao número de elementos dea
eb
respectivamente.Linha 7 : Em seguida, acrescente "0" após cada ponto para fazer máscaras de preenchimento.
Linha 9 : Variáveis locais:
w
- largura do itemfmt
- string de formato printf, a ser calculadax
- temporárioIFS=.
bash divide os valores das variáveis em '.'.Linha 10 : Calcular
w
a largura máxima do item, que será usada para alinhar itens para comparação lexicográfica. No nosso exemplo, w = 2.Linha 11 : Crie o formato de alinhamento de impressão substituindo cada caractere
$a.$b
por%${w}s
, ou seja, "3.6"> "3.5a" produz "% 2s% 2s% 2s% 2s".Linha 12 : "printf -v a" define o valor da variável
a
. Isso é equivalentea=sprintf(...)
em muitas linguagens de programação. Observe que aqui, por efeito do IFS =. os argumentos paraprintf
dividir em itens individuais.Os primeiros
printf
itens dea
são preenchidos à esquerda com espaços, enquanto itens "0" suficientes são acrescentadosbp
para garantir que a sequência resultantea
possa ser comparada significativamente com uma formatação semelhanteb
.Nota que acrescentar
bp
- nãoap
aai
causaap
ebp
pode ter diferentes comprimentos, então isso resulta ema
eb
ter comprimentos iguais.Com o segundo
printf
que acrescentar a letra parteal
paraa
com estofamento suficiente para permitir uma comparação significativa. Agoraa
está pronto para comparação comb
.Linha 13 : Igual à linha 12, mas para
b
.Linha 15 : Dividir casos de comparação entre operadores não integrados (
<=
e>=
) e internos.Linha 16 : Se o operador de comparação for
<=
testadoa<b or a=b
- respectivamente>=
a<b or a=b
Linha 17 : Teste para operadores de comparação internos.
<>
fonte
Estou usando o Linux (Yocto) incorporado com o BusyBox. O BusyBox
sort
não tem uma-V
opção (mas o BusyBoxexpr match
pode fazer expressões regulares). Então, eu precisava de uma versão comparada do Bash que funcionasse com essa restrição.Fiz o seguinte (semelhante à resposta de Dennis Williamson ) para comparar usando um tipo de algoritmo de "classificação natural". Ele divide a string em partes numéricas e partes não numéricas; ele compara as partes numéricas numericamente (portanto,
10
é maior que9
) e as partes não numéricas como uma comparação ASCII simples.Pode comparar números de versão mais complicados, como
1.2-r3
versus1.2-r4
1.2rc3
versus1.2r4
Observe que ele não retorna o mesmo resultado para alguns dos casos de canto na resposta de Dennis Williamson . Em particular:
Mas esses são casos extremos, e acho que os resultados ainda são razoáveis.
fonte
fonte
--check=silent
, sem a necessidade detest
, assim: #if printf '%s\n%s' 4.2.0 "$OVFTOOL_VERSION" | sort --version-sort -C
Essa também é uma
pure bash
solução, pois printf é um bash embutido.fonte
Para versão antiga / busybox
sort
. O formulário simples fornece aproximadamente o resultado e geralmente funciona.Isso é especialmente útil na versão que contém símbolos alfa como
fonte
Que tal agora? Parece funcionar?
fonte
Aqui está outra solução pura do bash sem chamadas externas:
E há uma solução ainda mais simples, se você tiver certeza de que as versões em questão não contêm zeros à esquerda após o primeiro ponto:
Isso funcionará para algo como 1.2.3 vs 1.3.1 vs 0.9.7, mas não funcionará com 1.2.3 vs 1.2.3.0 ou 1.01.1 vs 1.1.1
fonte
4.4.4 > 44.3
Aqui está um refinamento da resposta principal (Dennis), que é mais concisa e usa um esquema de valor de retorno diferente para facilitar a implementação de <= e> = com uma única comparação. Ele também compara tudo depois do primeiro caractere que não está em [0-9.] Lexicograficamente, então 1.0rc1 <1.0rc2.
fonte
Eu implementei outra função comparadora. Este tinha dois requisitos específicos: (i) eu não queria que a função falhasse usando,
return 1
mas emecho
vez disso; (ii) como estamos recuperando versões de uma versão de repositório git "1.0" deve ser maior que "1.0.2", o que significa que "1.0" vem do tronco.Sinta-se livre para comentar e sugerir melhorias.
fonte
Você pode usar a versão CLI para verificar as restrições da versão
Exemplo de script bash:
fonte
Encontrei e resolvi esse problema, para adicionar uma resposta adicional (e mais curta e mais simples) ...
Primeira nota: a comparação estendida do shell falhou, como você já deve saber ...
Usando o sort -t '.'- g (ou o sort -V, conforme mencionado por kanaka) para ordenar versões e comparação simples de strings do bash, encontrei uma solução. O arquivo de entrada contém versões nas colunas 3 e 4 que desejo comparar. Isso percorre a lista identificando uma correspondência ou se uma é maior que a outra. Espero que isso ainda ajude quem quiser fazer isso usando o bash da maneira mais simples possível.
Obrigado ao blog de Barry pela ideia de classificação ... ref: http://bkhome.org/blog/?viewDetailed=02199
fonte
É bem simples e pequeno.
fonte
echo -ne "$1\n$2"
porprintf '%s\n ' "$1" "$2"
. Também é melhor usar em$()
vez dos backtics.Graças à solução de Dennis, podemos estendê-la para permitir operadores de comparação '>', '<', '=', '==', '<=' e '> ='.
Podemos então usar operadores de comparação nas expressões como:
e teste apenas o verdadeiro / falso do resultado, como:
fonte
Aqui está outra versão pura do bash, um pouco menor que a resposta aceita. Ele apenas verifica se uma versão é menor ou igual a uma "versão mínima" e verifica sequências alfanuméricas lexicograficamente, o que geralmente fornece o resultado errado ("snapshot" não é posterior a "release", para dar um exemplo comum) . Funcionará bem para maior / menor.
fonte
Outra abordagem (versão modificada do @joynes) que compara versões pontilhadas, conforme solicitado na pergunta
(por exemplo, "1.2", "2.3.4", "1.0", "1.10.1" etc.).
O número máximo de posições deve ser conhecido com antecedência. A abordagem espera no máximo 3 posições de versão.
exemplo de uso:
retorna: 1, pois 1.10.1 é maior que 1.7
retorna: 0, pois 1.10.1 é menor que 1.11
fonte
Aqui está uma solução Bash pura que suporta revisões (por exemplo, '1.0-r1'), com base na resposta postada por Dennis Williamson . Ele pode ser facilmente modificado para suportar coisas como '-RC1' ou extrair a versão de uma string mais complexa, alterando a expressão regular.
Para detalhes sobre a implementação, consulte os comentários no código e / ou ative o código de depuração incluído:
fonte
Uau ... isso está na lista de perguntas antigas, mas acho que essa é uma resposta bastante elegante. Primeiro converta cada versão separada por pontos em sua própria matriz, usando a expansão de parâmetros do shell (consulte Expansão de parâmetros do shell ).
Agora, as duas matrizes têm o número da versão como uma sequência numérica em ordem de prioridade. Muitas das soluções acima levam você a partir daí, mas tudo deriva da observação de que a string de versão é apenas um número inteiro com uma base arbitrária. Podemos testar a localização do primeiro dígito desigual (como o strcmp faz para caracteres em uma string).
Isso ecoará um número negativo se a primeira versão for menor que a segunda, um zero se forem iguais e um número positivo se a primeira versão for maior. Alguma saída:
Casos degenerados como ".2" ou "3.0". não funciona (resultados indefinidos) e se houver caracteres não numéricos ao lado de '.' pode falhar (não foi testado), mas certamente será indefinido. Portanto, isso deve ser associado a uma função de limpeza ou verificação apropriada para formatação válida. Além disso, tenho certeza de que, com alguns ajustes, isso poderia ser mais robusto sem muita bagagem extra.
fonte
O crédito vai para @Shellman
fonte