Apakah ada cara untuk membandingkan string seperti itu pada bash, misalnya: 2.4.5
dan 2.8
dan 2.4.5.1
?
linux
bash
versioning
exabiche
sumber
sumber
bc
. Ini bukan teks angka.2.1 < 2.10
akan gagal dengan cara ini.Jawaban:
Ini adalah versi Bash murni yang tidak memerlukan utilitas eksternal apa pun:
Jalankan tes:
sumber
Please don't use it for software or documentation, since it is incompatible with the GNU GPL
: / but +1 untuk kode hebatJika Anda memiliki coreutils-7 (di Ubuntu Karmic tetapi tidak ceria) maka
sort
perintah Anda harus memiliki-V
opsi (versi sortir) yang dapat Anda gunakan untuk melakukan perbandingan:sumber
brew install coreutils
. Maka yang di atas hanya harus dimodifikasi untuk menggunakan gsort.sort
tidak memiliki-V
opsi.printf
daripadaecho -e
.sort
juga memiliki-C
atau--check=silent
, sehingga Anda dapat menulisverlte() { printf '%s\n%s' "$1" "$2" | sort -C -V }
; dan memeriksa ketat kurang dari yang lebih sederhana dilakukan sebagaiverlt() { ! verlte "$2" "$1" }
.Mungkin tidak ada cara yang benar secara universal untuk mencapai ini. Jika Anda mencoba membandingkan versi dalam sistem paket Debian, cobalah
dpkg --compare-versions <first> <relation> <second>.
sumber
dpkg --compare-versions "1.0" "lt" "1.2"
berarti 1,0 kurang dari 1,2. Hasil perbandingan$?
adalah0
jika benar sehingga Anda dapat menggunakannya langsung setelahif
pernyataan.GNU sort memiliki opsi untuk itu:
memberi:
sumber
echo -e "2.4.10\n2.4.9" | sort -n -t.
sort
tidak memiliki-V
opsi.printf '%s\n' "2.4.5" "2.8" "2.4.5.1" | sort -V
.coreutils 7+
.Nah jika Anda tahu jumlah bidang yang bisa Anda gunakan -kn, n dan dapatkan solusi super sederhana
sumber
-t
opsi hanya menerima tab karakter tunggal ... jika tidak,2.4-r9
akan berfungsi juga. Sayang sekali: /-g
menjadi-n
. Ada alasan mengapa tidak untuk contoh ini? Sebagai catatan ... untuk melakukan perbandingan jenis "lebih besar dari", Anda dapat memeriksa apakah jenis yang diinginkan sama dengan jenis yang sebenarnya ... misalnyadesired="1.9\n1.11"; actual="$(echo -e $desired |sort -t '.' -k 1,1 -k 2,2 -g)";
dan kemudian verifikasiif [ "$desired" = "$actual" ]
.Ini untuk paling banyak 4 bidang dalam versi.
sumber
printf "%03d%03d%03d%03d" $(echo "$1" | tr '.' '\n' | head -n 4)
head -n
dapat bekerja, saya harus berubah ketr '.' '\n'
tr
Output pipased 's/\(^\| \)0\([0-9][0-9]*\)/\1\2/g'
yang akan mengatasi hal itu (Agak canggung)Digunakan seperti itu:
(dari https://apple.stackexchange.com/a/123408/11374 )
sumber
Anda dapat membagi
.
dan membandingkan secara rekursif seperti yang ditunjukkan dalam algoritma berikut, diambil dari sini . Ini mengembalikan 10 jika versinya sama, 11 jika versi 1 lebih besar dari versi 2 dan 9 sebaliknya.Sumber
sumber
jika hanya untuk mengetahui apakah satu versi lebih rendah dari yang lain saya datang memeriksa apakah
sort --version-sort
mengubah urutan string versi saya:sumber
Saya menerapkan fungsi yang mengembalikan hasil yang sama seperti Dennis Williamson tetapi menggunakan lebih sedikit garis. Itu memang melakukan pemeriksaan kewarasan pada awalnya yang menyebabkan
1..0
gagal dari tesnya (yang saya berpendapat harus menjadi kasus) tetapi semua tes yang lain lulus dengan kode ini:sumber
Berikut adalah fungsi Bash sederhana yang tidak menggunakan perintah eksternal. Ini berfungsi untuk string versi yang memiliki hingga tiga bagian numerik di dalamnya - kurang dari 3 juga. Itu dapat dengan mudah diperpanjang untuk lebih. Ini alat
=
,<
,<=
,>
,>=
, dan!=
kondisi.Inilah tesnya:
Subset dari output tes:
sumber
V
- solusi bash murni, tidak ada utilitas eksternal yang diperlukan.=
==
!=
<
<=
>
dan>=
(leksikografis).1.5a < 1.5b
1.6 > 1.5b
if V 1.5 '<' 1.6; then ...
.<>
<>
Kode Dijelaskan
Baris 1 : Tentukan variabel lokal:
a
,op
,b
- operan perbandingan dan operator, yaitu, "3.6"> "3.5a".al
,bl
- huruf ekora
danb
, diinisialisasi ke item ekor, yaitu, "6" dan "5a".Baris 2, 3 : Digit pangkas kiri dari item ekor sehingga hanya huruf yang tersisa, jika ada, yaitu, "" dan "a".
Baris 4 : Potong kanan surat dari
a
danb
untuk meninggalkan hanya urutan item numerik sebagai variabel lokalai
danbi
, yaitu, "3,6" dan "3,5". Contoh penting: "4.01-RC2"> "4.01-RC1" menghasilkan ai = "4.01" al = "- RC2" dan bi = "4.01" bl = "- RC1".Baris 6 : Tentukan variabel lokal:
ap
,bp
- nol bantalan kanan untukai
danbi
. Mulailah dengan menjaga titik antar-item saja, yang jumlahnya sama dengan jumlah elemena
danb
masing - masing.Baris 7 : Kemudian tambahkan "0" setelah setiap titik untuk membuat masker padding.
Baris 9 : Variabel lokal:
w
- lebar barangfmt
- string format printf, harus dihitungx
- sementaraIFS=.
bash membagi nilai variabel di '.'Baris 10 : Hitung
w
, lebar item maksimum, yang akan digunakan untuk menyelaraskan item untuk perbandingan leksikografis. Dalam contoh kita, w = 2.Baris 11 : Buat format penyelarasan printf dengan mengganti setiap karakter
$a.$b
dengan%${w}s
, yaitu, "3.6"> "3.5a" menghasilkan "% 2s% 2s% 2s% 2s% 2s".Baris 12 : "printf -v a" menetapkan nilai variabel
a
. Ini setara dengana=sprintf(...)
banyak bahasa pemrograman. Perhatikan bahwa di sini, akibat IFS =. argumen untukprintf
dipecah menjadi item individual.Dengan
printf
item pertamaa
diisi dengan spasi sementara cukup "0" item ditambahkan daribp
untuk memastikan bahwa string yang dihasilkana
dapat bermakna dibandingkan dengan diformat samab
.Perhatikan bahwa kita menambahkan
bp
- tidakap
untukai
karenaap
danbp
mungkin memiliki lenghts berbeda, sehingga hasil inia
danb
memiliki panjang yang sama.Dengan kedua
printf
kita tambahkan bagian suratal
untuka
dengan cukup padding untuk memungkinkan perbandingan yang berarti. Sekaranga
siap untuk perbandinganb
.Baris 13 : Sama seperti baris 12 tetapi untuk
b
.Baris 15 : Membagi kasus perbandingan antara operator yang tidak built-in (
<=
dan>=
) dan built-in.Baris 16 : Jika operator pembanding
<=
kemudian menguji untuka<b or a=b
- masing-masing>=
a<b or a=b
Baris 17 : Tes untuk operator perbandingan internal.
<>
sumber
Saya menggunakan Linux tertanam (Yocto) dengan BusyBox. BusyBox
sort
tidak memiliki-V
opsi (tetapi BusyBoxexpr match
dapat melakukan ekspresi reguler). Jadi saya perlu membandingkan versi Bash yang bekerja dengan kendala itu.Saya telah membuat yang berikut (mirip dengan jawaban Dennis Williamson ) untuk membandingkan menggunakan jenis algoritma "natural sort". Ini membagi string menjadi bagian numerik dan bagian non-numerik; itu membandingkan bagian numerik secara numerik (jadi
10
lebih besar dari9
), dan membandingkan bagian non-numerik sebagai perbandingan ASCII biasa.Itu dapat membandingkan nomor versi yang lebih rumit seperti
1.2-r3
melawan1.2-r4
1.2rc3
melawan1.2r4
Perhatikan bahwa itu tidak mengembalikan hasil yang sama untuk beberapa kasus sudut dalam jawaban Dennis Williamson . Khususnya:
Tapi itu adalah kasus sudut, dan saya pikir hasilnya masih masuk akal.
sumber
sumber
--check=silent
, tanpa perlutest
, seperti ini:if printf '%s\n%s' 4.2.0 "$OVFTOOL_VERSION" | sort --version-sort -C
Ini juga
pure bash
solusi, karena printf adalah bash builtin.sumber
Untuk versi lama / busybox
sort
. Bentuk sederhana memberikan hasil yang kasar dan sering berfungsi.Ini berguna khusus pada versi yang berisi simbol alfa seperti
sumber
Bagaimana dengan ini? Tampaknya bekerja?
sumber
Berikut ini adalah solusi bash murni lainnya tanpa panggilan eksternal:
Dan bahkan ada solusi yang lebih sederhana, jika Anda yakin bahwa versi yang dipermasalahkan tidak mengandung nol di depan setelah titik pertama:
Ini akan bekerja untuk sesuatu seperti 1.2.3 vs 1.3.1 vs 0.9.7, tetapi tidak akan bekerja dengan 1.2.3 vs 1.2.3.0 atau 1.01.1 vs 1.1.1
sumber
4.4.4 > 44.3
Berikut adalah penyempurnaan dari jawaban teratas (Dennis's) yang lebih ringkas dan menggunakan skema nilai pengembalian yang berbeda untuk membuatnya mudah diterapkan <= dan> = dengan satu perbandingan. Itu juga membandingkan semuanya setelah karakter pertama tidak dalam [0-9.] Leksikografis, jadi 1.0rc1 <1.0rc2.
sumber
Saya menerapkan fungsi pembanding lain. Yang ini memiliki dua persyaratan khusus: (i) Saya tidak ingin fungsi gagal dengan menggunakan
return 1
tetapiecho
sebaliknya; (ii) karena kita mengambil versi dari repositori git versi "1.0" harus lebih besar dari "1.0.2", yang berarti bahwa "1.0" berasal dari trunk.Jangan ragu untuk berkomentar dan menyarankan perbaikan.
sumber
Anda dapat menggunakan versi CLI untuk memeriksa batasan versi
Contoh skrip Bash:
sumber
Saya menemukan dan memecahkan masalah ini, untuk menambahkan jawaban tambahan (dan lebih pendek dan lebih sederhana) ...
Catatan pertama, perbandingan shell diperpanjang gagal karena Anda mungkin sudah tahu ...
Menggunakan sort -t '.'-g (atau sort -V seperti yang disebutkan oleh kanaka) untuk memesan versi dan perbandingan string bash sederhana, saya menemukan solusinya. File input berisi versi dalam kolom 3 dan 4 yang ingin saya bandingkan. Ini berulang melalui daftar mengidentifikasi kecocokan atau jika satu lebih besar dari yang lain. Semoga ini masih dapat membantu orang yang ingin melakukan ini menggunakan bash sesederhana mungkin.
Berkat blog Barry untuk ide pengurutan ... ref: http://bkhome.org/blog/?viewDetailed=02199
sumber
Sederhana dan kecil.
sumber
echo -ne "$1\n$2"
denganprintf '%s\n ' "$1" "$2"
. Juga lebih baik menggunakan$()
daripada backtics.Berkat solusi Dennis, kami dapat memperluasnya untuk memungkinkan operator perbandingan '>', '<', '=', '==', '<=', dan '> ='.
Kami kemudian dapat menggunakan operator perbandingan dalam ekspresi seperti:
dan hanya menguji benar / salah hasilnya, seperti:
sumber
Ini versi lain dari bash murni, lebih kecil dari pada jawaban yang diterima. Hanya memeriksa apakah suatu versi kurang dari atau sama dengan "versi minimum", dan itu akan memeriksa urutan alfanumerik secara leksikografis, yang sering memberikan hasil yang salah ("snapshot" tidak lebih dari "rilis", untuk memberikan contoh umum) . Ini akan berfungsi dengan baik untuk mayor / minor.
sumber
Pendekatan lain (versi modifikasi dari @joynes) yang membandingkan versi bertitik seperti yang ditanyakan dalam pertanyaan
(yaitu "1.2", "2.3.4", "1.0", "1.10.1", dll.).
Jumlah posisi maksimum harus diketahui sebelumnya. Pendekatan ini mengharapkan posisi versi maksimal 3.
contoh penggunaan:
pengembalian: 1 sejak 1.10.1 lebih besar dari 1.7
pengembalian: 0 sejak 1.10.1 lebih rendah dari 1.11
sumber
Inilah solusi Bash murni yang mendukung revisi (mis. '1.0-r1'), berdasarkan jawaban yang diposting oleh Dennis Williamson . Ini dapat dengan mudah dimodifikasi untuk mendukung hal-hal seperti '-RC1' atau mengekstrak versi dari string yang lebih kompleks dengan mengubah ekspresi reguler.
Untuk detail tentang implementasi, silakan merujuk komentar dalam kode dan / atau mengaktifkan kode debug yang disertakan:
sumber
Wow ... ini jauh dari daftar pertanyaan lama, tapi saya pikir ini adalah jawaban yang cukup elegan. Pertama-tama konversikan setiap versi yang dipisahkan oleh titik menjadi lariknya sendiri, menggunakan ekspansi parameter shell (Lihat Ekspansi Parameter Shell ).
Sekarang kedua array memiliki nomor versi sebagai string numerik dalam urutan prioritas. Banyak solusi di atas membawa Anda dari sana, tetapi semuanya berasal dari pengamatan bahwa string versi hanyalah bilangan bulat dengan basis sewenang-wenang. Kita dapat menguji menemukan digit tidak sama pertama (seperti strcmp untuk karakter dalam string).
Ini menggemakan angka negatif jika versi pertama kurang dari yang kedua, nol jika mereka sama dan angka positif jika versi pertama lebih besar. Beberapa output:
Kasus degenerasi seperti, ".2" atau "3.0." tidak berfungsi (hasil yang tidak ditentukan), dan jika ada karakter non-numerik di sebelah tanda '.' mungkin gagal (belum diuji) tetapi pasti tidak akan ditentukan. Jadi ini harus dipasangkan dengan fungsi sanitasi atau pemeriksaan yang sesuai untuk pemformatan yang valid. Juga, saya yakin dengan beberapa penyesuaian, ini bisa dibuat lebih kuat tanpa terlalu banyak bagasi tambahan.
sumber
Kredit jatuh ke @Shellman
sumber