Czy istnieje sposób na porównanie takich ciągów w bashu, np .: 2.4.5
i 2.8
i 2.4.5.1
?
linux
bash
versioning
exabiche
źródło
źródło
bc
. To tekst, a nie liczby.2.1 < 2.10
zawiodłaby w ten sposób.Odpowiedzi:
Oto czysta wersja Bash, która nie wymaga żadnych zewnętrznych narzędzi:
Uruchom testy:
źródło
Please don't use it for software or documentation, since it is incompatible with the GNU GPL
: / ale +1 za świetny kodJeśli masz coreutils-7 (w Ubuntu Karmic, ale nie Jaunty), twoje
sort
polecenie powinno mieć-V
opcję (sortowanie wersji), której możesz użyć do porównania:źródło
brew install coreutils
. Następnie powyższe należy po prostu zmodyfikować, aby używać gsort.sort
nie ma-V
opcji.printf
zamiastecho -e
.sort
ma również-C
lub--check=silent
, więc możesz pisaćverlte() { printf '%s\n%s' "$1" "$2" | sort -C -V }
; i sprawdzanie ścisłe mniej niż jest to prostsze jakoverlt() { ! verlte "$2" "$1" }
.Prawdopodobnie nie ma uniwersalnie poprawnego sposobu, aby to osiągnąć. Jeśli próbujesz porównać wersje w systemie pakietów Debiana, spróbuj
dpkg --compare-versions <first> <relation> <second>.
źródło
dpkg --compare-versions "1.0" "lt" "1.2"
oznacza 1,0 mniej niż 1,2. Wynik porównania$?
jest0
prawdziwy, więc możesz go użyć bezpośrednio poif
wyrażeniu.GNU sort ma do tego opcję:
daje:
źródło
echo -e "2.4.10\n2.4.9" | sort -n -t.
sort
nie ma-V
opcji.printf '%s\n' "2.4.5" "2.8" "2.4.5.1" | sort -V
.coreutils 7+
.Cóż, jeśli znasz liczbę pól, możesz użyć -kn, n i uzyskać super proste rozwiązanie
źródło
-t
opcja akceptuje tylko pojedyncze tabulatory ... w przeciwnym2.4-r9
razie działałaby również. Jaka szkoda: /-g
na-n
. Jakiś powód, dlaczego nie w tym przykładzie? Na marginesie ... aby przeprowadzić porównanie typu „większe niż”, możesz sprawdzić, czy żądane sortowanie jest takie samo jak rzeczywiste sortowanie ... np.desired="1.9\n1.11"; actual="$(echo -e $desired |sort -t '.' -k 1,1 -k 2,2 -g)";
A następnie zweryfikowaćif [ "$desired" = "$actual" ]
.Dotyczy to maksymalnie 4 pól w wersji.
źródło
printf "%03d%03d%03d%03d" $(echo "$1" | tr '.' '\n' | head -n 4)
head -n
pracować, musiałem zmienić się natr '.' '\n'
tr
Wyjście rurowe, przezsed 's/\(^\| \)0\([0-9][0-9]*\)/\1\2/g'
które się tym zajmie (raczej niezgrabnie)Używany jako taki:
(z https://apple.stackexchange.com/a/123408/11374 )
źródło
Możesz rekurencyjnie podzielić
.
i porównać, jak pokazano na poniższym algorytmie, zaczerpniętym stąd . Zwraca 10, jeśli wersje są takie same, 11, jeśli wersja 1 jest większa niż wersja 2 i 9 w przeciwnym razie.Źródło
źródło
jeśli chce się tylko dowiedzieć, czy jedna wersja jest niższa od innej, wymyśliłem sprawdzenie, czy
sort --version-sort
zmienia kolejność ciągów moich wersji:źródło
Zaimplementowałem funkcję, która zwraca te same wyniki, co Dennis Williamson, ale używa mniej wierszy. Na początku przeprowadza kontrolę poczytalności, co powoduje,
1..0
że jego testy kończą się niepowodzeniem (co moim zdaniem powinno mieć miejsce), ale wszystkie inne testy przechodzą z tym kodem:źródło
Oto prosta funkcja Bash, która nie używa zewnętrznych poleceń. Działa w przypadku ciągów wersji, które mają do trzech części numerycznych - mniej niż 3 jest również w porządku. Można go łatwo rozszerzyć na więcej. Realizuje
=
,<
,<=
,>
,>=
, i!=
warunki.Oto test:
Podzbiór wyników testu:
źródło
V
- czyste rozwiązanie bash, bez zewnętrznych narzędzi.=
==
!=
<
<=
>
i>=
(leksykograficzny).1.5a < 1.5b
1.6 > 1.5b
if V 1.5 '<' 1.6; then ...
.<>
<>
Kod wyjaśniony
Linia 1 : Zdefiniuj zmienne lokalne:
a
,op
,b
- argumenty porównania i operator, czyli "3.6"> "3.5a".al
,bl
- końcówki litera
ib
, zainicjowane w pozycji końcowej, tj. „6” i „5a”.Wiersze 2, 3 : Przycinaj w lewo cyfry z elementów końcowych, tak aby pozostały tylko litery, jeśli istnieją, tj. „” I „a”.
Linia 4 : prawy wykończenia listów od
a
ib
pozostawić tylko kolejność elementów liczbowych jako zmienne lokalneai
ibi
, czyli „3.6” i „3.5”. Godny uwagi przykład: "4.01-RC2"> "4.01-RC1" daje ai = "4.01" al = "- RC2" i bi = "4.01" bl = "- RC1".Wiersz 6 : Zdefiniuj zmienne lokalne:
ap
,bp
- zero dopełnień w prawo dlaai
ibi
. Zacznij od pozostawienia tylko kropek między pozycjami, których liczba jest równa liczbie elementów odpowiednioa
ib
.Linia 7 : Następnie dodaj „0” po każdej kropce, aby utworzyć maski wypełniające.
Wiersz 9 : Zmienne lokalne:
w
- szerokość przedmiotufmt
- ciąg formatu printf do obliczeniax
- tymczasoweIFS=.
bash dzieli wartości zmiennych w „.”.Wiersz 10 : Oblicz
w
, maksymalna szerokość elementu, która zostanie użyta do wyrównania elementów w celu porównania leksykograficznego. W naszym przykładzie w = 2.Linia 11 : Tworzenie formatu printf wyrównania zastępując każdy znak
$a.$b
z%${w}s
, czyli "3.6"> "3.5A" plony "% 2s 2s%%% 2s 2s".Linia 12 : "printf -v a" ustawia wartość zmiennej
a
. Jest to odpowiednika=sprintf(...)
w wielu językach programowania. Zauważ, że tutaj, w wyniku IFS =. argumenty doprintf
podzielenia na poszczególne pozycje.Pierwsze
printf
elementya
są dopełniane spacjami z lewej strony, podczas gdy wystarczająca liczba elementów „0” jest dodawanych z,bp
aby zapewnić, że wynikowy ciąga
można w znaczący sposób porównać z podobnie sformatowanymb
.Należy pamiętać, że mamy dołączyć
bp
- nieap
doai
ponieważap
ibp
mogą mieć różne długościach, tak Powodujea
ib
o równych długościach.W drugim
printf
dodajemy część literowąal
doa
z wystarczającym wypełnieniem, aby umożliwić sensowne porównanie. Teraza
jest gotowy do porównania zb
.Linia 13 : taka sama jak linia 12, ale dla
b
.Wiersz 15 : Podziel przypadki porównania między operatorami niewbudowanymi (
<=
i>=
) i wbudowanymi.Wiersz 16 : Jeśli operator porównania jest
<=
następnie testowany dlaa<b or a=b
- odpowiednio>=
a<b or a=b
Wiersz 17 : Test dla wbudowanych operatorów porównania.
<>
źródło
Używam wbudowanego systemu Linux (Yocto) z BusyBox. BusyBox
sort
nie ma-V
opcji (ale BusyBoxexpr match
może wykonywać wyrażenia regularne). Potrzebowałem więc porównania wersji Bash, które działało z tym ograniczeniem.Dokonałem następującego (podobnego do odpowiedzi Dennisa Williamsona ) porównania przy użyciu algorytmu „sortowania naturalnego”. Dzieli ciąg na części numeryczne i nienumeryczne; porównuje części numeryczne numerycznie (więc
10
jest większe niż9
) i porównuje części nienumeryczne jako zwykłe porównanie ASCII.Może porównywać bardziej skomplikowane numery wersji, takie jak
1.2-r3
przeciw1.2-r4
1.2rc3
przeciw1.2r4
Zauważ, że nie zwraca tego samego wyniku w niektórych przypadkach narożnych w odpowiedzi Dennisa Williamsona . W szczególności:
Ale to są narożne przypadki i myślę, że wyniki są nadal rozsądne.
źródło
źródło
--check=silent
, bez potrzebytest
, w ten sposób:if printf '%s\n%s' 4.2.0 "$OVFTOOL_VERSION" | sort --version-sort -C
Jest to również
pure bash
rozwiązanie, ponieważ printf jest wbudowaną funkcją bash.źródło
Dla starej wersji / busybox
sort
. Prosta forma daje z grubsza wynik i często działa.Jest to szczególnie przydatne w wersji, która zawiera symbole alfa, takie jak
źródło
Co powiesz na to? Wydaje się, że działa?
źródło
Oto kolejne czyste rozwiązanie bash bez żadnych połączeń zewnętrznych:
A rozwiązanie jest jeszcze prostsze, jeśli masz pewność, że omawiane wersje nie zawierają zer wiodących po pierwszej kropce:
To zadziała dla czegoś takiego jak 1.2.3 vs 1.3.1 vs 0.9.7, ale nie zadziała z 1.2.3 vs 1.2.3.0 lub 1.01.1 vs 1.1.1
źródło
4.4.4 > 44.3
Oto udoskonalenie pierwszej odpowiedzi (Dennisa), która jest bardziej zwięzła i wykorzystuje inny schemat wartości zwracanych, aby ułatwić implementację <= i> = za pomocą pojedynczego porównania. Porównuje również wszystko po pierwszym znaku nie w [0-9.] Leksykograficznie, więc 1.0rc1 <1.0rc2.
źródło
Zaimplementowałem jeszcze jedną funkcję komparatora. Ten miał dwa szczególne wymagania: (i) nie chciałem, aby funkcja zawiodła przy użyciu,
return 1
aleecho
zamiast tego; (ii) gdy pobieramy wersje z repozytorium git, wersja „1.0” powinna być większa niż „1.0.2”, co oznacza, że „1.0” pochodzi z trunk.Zapraszam do komentowania i sugerowania ulepszeń.
źródło
Możesz użyć interfejsu wiersza polecenia wersji, aby sprawdzić ograniczenia wersji
Przykład skryptu Bash:
źródło
Natknąłem się i rozwiązałem ten problem, aby dodać dodatkową (i krótszą i prostszą) odpowiedź ...
Pierwsza uwaga, rozszerzone porównanie powłok nie powiodło się, jak być może już wiesz ...
Używając sort -t '.'- g (lub sort -V, jak wspomniało kanaka), aby uporządkować wersje i proste porównanie łańcuchów bash, znalazłem rozwiązanie. Plik wejściowy zawiera wersje w kolumnach 3 i 4, które chcę porównać. Powoduje to iterację listy identyfikującej dopasowanie lub czy jeden jest większy od drugiego. Mam nadzieję, że może to nadal pomóc każdemu, kto chce to zrobić przy użyciu tak prostego basha, jak to tylko możliwe.
Podziękowania dla bloga Barry'ego za pomysł sortowania ... ref: http://bkhome.org/blog/?viewDetailed=02199
źródło
To całkiem proste i małe.
źródło
echo -ne "$1\n$2"
zprintf '%s\n ' "$1" "$2"
. Lepiej też używać$()
zamiast backtics.Dzięki rozwiązaniu Dennisa możemy go rozszerzyć o operatory porównania '>', '<', '=', '==', '<=' i '> ='.
Możemy wtedy użyć operatorów porównania w wyrażeniach takich jak:
i testuj tylko prawda / fałsz wyniku, na przykład:
źródło
Oto kolejna czysta wersja basha, raczej mniejsza niż akceptowana odpowiedź. Sprawdza tylko, czy wersja jest mniejsza lub równa „wersji minimalnej” i sprawdza leksykograficznie ciągi alfanumeryczne, co często daje błędny wynik („migawka” nie jest późniejsza niż „wydanie”, aby podać typowy przykład) . Będzie działać dobrze dla dur / moll.
źródło
Inne podejście (zmodyfikowana wersja @joynes), które porównuje wersje z kropkami zgodnie z pytaniem
(np. „1.2”, „2.3.4”, „1.0”, „1.10.1” itp.).
Maksymalna liczba pozycji musi być wcześniej znana. Podejście przewiduje maksymalnie 3 pozycje wersji.
przykład użycia:
zwraca: 1, ponieważ 1,10.1 jest większe niż 1,7
zwraca: 0, ponieważ 1,10,1 jest mniejsze niż 1,11
źródło
Oto czyste rozwiązanie Bash, które obsługuje wersje (np. „1.0-r1”), na podstawie odpowiedzi opublikowanej przez Dennisa Williamsona . Można go łatwo zmodyfikować, aby obsługiwał takie rzeczy, jak „-RC1” lub wyodrębnić wersję z bardziej złożonego ciągu, zmieniając wyrażenie regularne.
Aby uzyskać szczegółowe informacje dotyczące implementacji, zapoznaj się z komentarzami w kodzie i / lub włącz dołączony kod debugowania:
źródło
Wow ... to daleko w dół listy starego pytania, ale myślę, że to całkiem elegancka odpowiedź. Najpierw przekonwertuj każdą wersję rozdzielaną kropkami na własną tablicę, używając rozwijania parametrów powłoki (zobacz Rozszerzanie parametrów powłoki ).
Teraz dwie tablice mają numer wersji jako ciąg liczbowy w kolejności priorytetu. Wiele z powyższych rozwiązań prowadzi cię stamtąd, ale wszystko to wynika z obserwacji, że łańcuch wersji jest po prostu liczbą całkowitą o dowolnej podstawie. Możemy przetestować znalezienie pierwszej nierównej cyfry (tak jak robi to strcmp dla znaków w ciągu).
Powoduje to powtórzenie liczby ujemnej, jeśli pierwsza wersja jest mniejsza niż druga, zero, jeśli są równe, i liczbę dodatnią, jeśli pierwsza wersja jest większa. Niektóre dane wyjściowe:
Zdegenerowane przypadki, takie jak „.2” lub „3.0”. nie działa (niezdefiniowane wyniki) i jeśli obok znaku „.” znajdują się znaki nienumeryczne. może się nie powieść (nie zostało przetestowane), ale z pewnością będzie niezdefiniowane. Dlatego należy to połączyć z funkcją odkażania lub odpowiednim sprawdzeniem poprawności formatowania. Jestem też pewien, że dzięki pewnym poprawkom można to uczynić bardziej wytrzymałym bez zbytniego dodatkowego bagażu.
źródło
Kredyt trafia do @Shellman
źródło