Cara membandingkan string di Bash


Jawaban:


1376

Menggunakan variabel dalam pernyataan if

if [ "$x" = "valid" ]; then
  echo "x has the value 'valid'"
fi

Jika Anda ingin melakukan sesuatu ketika mereka tidak cocok, ganti =dengan !=. Anda dapat membaca lebih lanjut tentang operasi string dan operasi aritmatika dalam dokumentasi masing-masing.

Mengapa kami menggunakan tanda kutip di sekitar $x?

Anda ingin mengutipnya $x, karena jika kosong, skrip Bash Anda menemui kesalahan sintaksis seperti terlihat di bawah:

if [ = "valid" ]; then

Penggunaan ==operator yang tidak standar

Perhatikan bahwa Bash memungkinkan ==untuk digunakan untuk kesetaraan dengan [, tetapi ini bukan standar .

Gunakan kasus pertama dimana kutipan di sekitar $xadalah opsional:

if [[ "$x" == "valid" ]]; then

atau gunakan kasus kedua:

if [ "$x" = "valid" ]; then

12
Bagaimana hal itu terkait dengan jawaban yang diterima yang diberikan dalam kesalahan operator yang tidak terduga ? Saya mendapat kesalahan yang sama saat menggunakan [ "$1" == "on" ]. Mengubah ini ke ["$ 1" = "on"] menyelesaikan masalah.
Piotr Dobrogost

78
Ruang dibutuhkan.
TAAPSogeking

6
@JohnFeminella Saat menulis dalam skrip bash, seharusnya ada satu =dan bukan dua.
user13107

73
mungkin perlu dicatat bahwa Anda tidak dapat menggunakannya [ $x -eq "valid" ]. -eqadalah operator pembanding untuk bilangan bulat, bukan string.
craq

2
@Alex, Dalam kasus apa (jika pernah) saya perlu menggunakan pola ["x$yes" == "xyes"], yaitu awalan variabel dan string literal dengan x? Apakah itu peninggalan zaman dulu atau apakah itu benar-benar diperlukan dalam beberapa situasi?
lanoxx

142

Atau, jika Anda tidak perlu klausa lain:

[ "$x" == "valid" ] && echo "x has the value 'valid'"

71
Dan jika Anda memang membutuhkan klausa lain dan ingin membuat satu kalimat gila: ["$ x" == "valid"] && echo "valid" || gema "tidak valid"
Matt White

11
@ MatWhite: ini biasanya ide yang buruk, karena echobisa gagal.
gniourf_gniourf

1
bahkan, adachacha yang mungkin muncul, cara-cara yang indah dan elegan dari kedua marko && MattWhite
Deko

3
@ gniourf_gniourf, tidak masalah, gunakan [ "$X" == "valid" ] || ( echo invalid && false ) && echo "valid" .
12431234123412341234123

4
@ 12431234123412341234123 { echo invalid && false; }lebih efisien daripada ( echo invalid && false ), karena menghindari membayar untuk subkulit yang tidak perlu.
Charles Duffy

84
a="abc"
b="def"

# Equality Comparison
if [ "$a" == "$b" ]; then
    echo "Strings match"
else
    echo "Strings don't match"
fi

# Lexicographic (greater than, less than) comparison.
if [ "$a" \< "$b" ]; then
    echo "$a is lexicographically smaller then $b"
elif [ "$a" \> "$b" ]; then
    echo "$b is lexicographically smaller than $a"
else
    echo "Strings are equal"
fi

Catatan:

  1. Spasi antara ifdan [dan ]itu penting
  2. >dan <merupakan operator pengalihan jadi lepas dengan \>dan \<masing-masing untuk string.

6
Terima kasih atas perbandingan urutan abjad string
shadi

Masalah saya adalah bahwa $asebenarnya telah " "mengelilinginya sebagai bagian dari nilai literal string, oleh karena itu saya harus menggunakan karakter pelarian $buntuk membandingkan nilai. Saya dapat menemukan ini setelah berjalan bash -x ./script.sh, flag -x memungkinkan Anda untuk melihat nilai dari setiap eksekusi dan membantu dalam debug.
ShahNewazKhan

Perhatikan bahwa perbandingan urutan alfabet tidak terstandarisasi POSIX, sehingga tidak dijamin berfungsi pada platform non-GNU / shell non-bash. Hanya operasi di pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html dijamin portabel.
Charles Duffy

62

Untuk membandingkan string dengan penggunaan wildcard

if [[ "$stringA" == *$stringB* ]]; then
  # Do something here
else
  # Do Something here
fi

12
Penting bahwa wildcard hanya dapat digunakan di sisi kanan! Perhatikan juga yang hilang di "sekitar wildcard. (btw: +1 untuk wildcard!)
Scz

6
Ekspansi $stringB harus dikutip (dan, kebetulan, sisi kiri tidak perlu dikutip): if [[ $stringA = *"$stringB"* ]]; then.
gniourf_gniourf

Saya mencoba untuk menggunakan logika wildcard yang sama untuk nama file di filepath. Tetapi itu tidak berhasil untuk saya. mencoba semua string wildcard berbeda yang disediakan di sini. tetapi selalu terjadi pada kasus lain. stringA dalam kasus saya adalah path file / tmp / file dan stringB adalah "file".
hujan

35

Saya harus tidak setuju salah satu komentar di satu titik:

[ "$x" == "valid" ] && echo "valid" || echo "invalid"

Tidak, itu bukan oneliner yang gila

Itu hanya terlihat seperti satu untuk, hmm, yang belum tahu ...

Ini menggunakan pola umum sebagai bahasa, dengan cara;

Dan setelah Anda mempelajari bahasa itu.

Sebenarnya, itu enak dibaca

Ini adalah ekspresi logis sederhana, dengan satu bagian khusus: evaluasi malas dari operator logika.

[ "$x" == "valid" ] && echo "valid" || echo "invalid"

Setiap bagian adalah ekspresi logis; yang pertama mungkin benar atau salah, dua lainnya selalu benar.

(
[ "$x" == "valid" ] 
&&
echo "valid"
)
||
echo "invalid"

Sekarang, ketika dievaluasi, yang pertama diperiksa. Jika salah, maka operan kedua dari logika dan && setelah itu tidak relevan. Yang pertama tidak benar, jadi tidak mungkin yang pertama dan yang kedua benar.
Sekarang, dalam hal ini adalah sisi pertama dari logika atau || salah, tetapi bisa jadi benar jika pihak lain - bagian ketiga - benar.

Jadi bagian ketiga akan dievaluasi - terutama menulis pesan sebagai efek samping. (Ini memiliki hasil yang 0benar, yang tidak kita gunakan di sini)

Kasus-kasus lain serupa, tetapi lebih sederhana - dan - saya berjanji! adalah - bisa - mudah dibaca!
(Saya tidak punya, tapi saya pikir menjadi veteran UNIX dengan janggut abu-abu sangat membantu dalam hal ini.)


17
Itu ... && ... || ...biasanya disukai (maaf veteran Unix greybeard, Anda telah salah selama ini), karena itu tidak setara secara semantik if ... then ... else .... Jangan khawatir, ini adalah perangkap umum .
gniourf_gniourf

6
@ gniourf_gniourf OP tidak salah - mereka juga mungkin tidak tahu seperti yang Anda sarankan. ... && ... || ...adalah pola yang benar-benar valid dan idiom bash yang umum. Penggunaannya memang menentukan pengetahuan sebelumnya (yang mungkin baik untuk diingat jika ada pemula di antara hadirin), tetapi OP memiliki rambut untuk membuktikan bahwa mereka tahu bagaimana menghindari penutup lubang got terbuka.
ebpa

3
@ebpa Bagaimana jika pernyataan berikut && mengembalikan nilai false, eksekusi akan dilanjutkan dengan pernyataan berikut || ? Jika demikian, itu salah dan mungkin itulah yang disarankan gniourf
TSG

4
Saya pikir gema hanyalah sebuah contoh. Pernyataan berikut && mungkin masih mengembalikan nilai bukan nol
TSG

2
@gniourf_gniourf +1 untuk memposting tautan ke Bash Pitfalls! Sangat berguna!
Jaguar

21

Anda juga dapat menggunakan use case / esac

case "$string" in
 "$pattern" ) echo "found";;
esac

Apakah ini setara atau mengandung?
ytpillai

@ytpillai, ini adalah persamaan. Ingatlah bahwa Anda dapat memiliki pola yang dipisahkan oleh |, sebelum ). The inpernyataan setara dengan thendi ifpernyataan. Anda bisa berargumen ini bekerja di atas daftar pola, di mana setiap daftar memiliki pernyataan sendiri tentang apa yang harus dilakukan, jika Anda berasal dari Python. Bukan suka substring in string, tapi lebih tepatnya for item in list. Gunakan *sebagai pernyataan terakhir Anda jika Anda menginginkan suatu elsekondisi. Ia kembali pada pertemuan pertama.
mazunki

18

Script berikut membaca dari file bernama "testonthis" baris demi baris dan kemudian membandingkan setiap baris dengan string sederhana, string dengan karakter khusus dan ekspresi reguler. Jika tidak cocok, maka skrip akan mencetak garis, jika tidak tidak.

Ruang di Bash sangat penting. Jadi yang berikut ini akan berhasil:

[ "$LINE" != "table_name" ] 

Tetapi yang berikut tidak akan:

["$LINE" != "table_name"] 

Jadi silakan gunakan apa adanya:

cat testonthis | while read LINE
do
if [ "$LINE" != "table_name" ] && [ "$LINE" != "--------------------------------" ] && [[ "$LINE" =~ [^[:space:]] ]] && [[ "$LINE" != SQL* ]]; then
echo $LINE
fi
done

Gunakan pendekatan ini untuk melihat file. Yaitu, menghapus UUoC antara lain.
fedorqui 'SO stop harming'

Itu tidak penting karena bashtetapi karena [sebenarnya biner eksternal (seperti dalam which [menghasilkan sesuatu seperti /usr/bin/[)
Patrick Bergner

11

Saya mungkin akan menggunakan pencocokan regexp jika input hanya memiliki beberapa entri yang valid. Misalnya hanya "mulai" dan "berhenti" adalah tindakan yang valid.

if [[ "${ACTION,,}" =~ ^(start|stop)$ ]]; then
  echo "valid action"
fi

Perhatikan bahwa saya mengurangi variabel $ACTIONdengan menggunakan koma ganda. Perhatikan juga bahwa ini tidak akan berfungsi pada versi bash yang terlalu tua di luar sana.


9

Bash 4+ contoh. Catatan: tidak menggunakan tanda kutip akan menyebabkan masalah ketika kata-kata mengandung spasi, dll. Selalu kutip di Bash, IMO.

Berikut beberapa contoh di Bash 4+:

Contoh 1, periksa 'ya' dalam string (case-sensitive):

    if [[ "${str,,}" == *"yes"* ]] ;then

Contoh 2, periksa 'ya' dalam string (case-sensitive):

    if [[ "$(echo "$str" | tr '[:upper:]' '[:lower:]')" == *"yes"* ]] ;then

Contoh 3, periksa 'ya' dalam string (peka huruf besar kecil):

     if [[ "${str}" == *"yes"* ]] ;then

Contoh 4, periksa 'ya' dalam string (peka huruf besar kecil):

     if [[ "${str}" =~ "yes" ]] ;then

Contoh 5, pencocokan tepat (peka huruf besar-kecil):

     if [[ "${str}" == "yes" ]] ;then

Contoh 6, kecocokan persis (tidak sensitif huruf besar):

     if [[ "${str,,}" == "yes" ]] ;then

Contoh 7, kecocokan persis:

     if [ "$a" = "$b" ] ;then

Nikmati.


bagi saya (mac GNU bash versi 4.4.12 (1) -release x86_64-apple-darwin17.0.0), saya harus menggunakan if [ "$a"="$b" ]atau tidak bekerja ... tidak dapat memiliki ruang di sekitar yang sama
spektrum

1

Saya melakukannya dengan cara ini yang kompatibel dengan Bash dan Dash (sh):

testOutput="my test"
pattern="my"

case $testOutput in (*"$pattern"*)
    echo "if there is a match"
    exit 1
    ;;
(*)
   ! echo there is no coincidence!
;;esac

apa perbedaan antara menggunakan (vs sebelumnya tidak menggunakannya?
mazunki
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.