Uji apakah string berisi substring


40

Saya punya kodenya

file="JetConst_reco_allconst_4j2t.png"
if [[ $file == *_gen_* ]];
then
    echo "True"
else
    echo "False"
fi

Saya menguji apakah filemengandung "gen". Outputnya "Salah". Bagus!

Masalahnya adalah ketika saya mengganti "gen" dengan variabel testseq:

file="JetConst_reco_allconst_4j2t.png"
testseq="gen"
if [[ $file == *_$testseq_* ]];
then
    echo "True"
else
    echo "False"
fi

Sekarang hasilnya adalah "Benar". Bagaimana mungkin? Bagaimana cara mengatasi masalah?


Jawaban:


25

Anda perlu menginterpolasi $testseqvariabel dengan salah satu cara berikut:

  • $file == *_"$testseq"_*(di sini $testseqdianggap sebagai string tetap)

  • $file == *_${testseq}_*(di sini $testseqdianggap sebagai pola).

Atau _segera setelah nama variabel akan diambil sebagai bagian dari nama variabel (itu adalah karakter yang valid dalam nama variabel).


Jawaban yang benar karena berlaku untuk OP, tetapi tanpa portable. (Ini bukan kritik atas jawaban yang diberikan, hanya peringatan bagi pembaca). ;-)
Cbhihe

28

Gunakan =~operator untuk membuat perbandingan ekspresi reguler:

#!/bin/bash
file="JetConst_reco_allconst_4j2t.png"
testseq="gen"
if [[ $file =~ $testseq ]];
then
    echo "True"
else
    echo "False"
fi

Dengan cara ini, ia akan membandingkan jika $fileada $testseqpada isinya.

user@host:~$ ./string.sh
False

Jika saya berubah testseq="Const":

user@host:~$ ./string.sh
True

Tapi, berhati-hatilah dengan apa yang Anda makan $testseq. Jika string di atasnya menunjukkan beberapa regex (seperti [0-9]misalnya), ada lebih banyak kesempatan untuk memicu "kecocokan".

Referensi :


20
file="JetConst_reco_allconst_4j2t.png"
testseq="gen"

case "$file" in
    *_"$testseq"_*) echo 'True'  ;;
    *)              echo 'False'
esac

Menggunakan case ... esacadalah salah satu cara paling sederhana untuk melakukan pencocokan pola dengan cara portabel. Ia bekerja sebagai "switch" pernyataan dalam bahasa lain ( bash, zsh, dan ksh93juga memungkinkan Anda untuk melakukan jatuh-melalui berbagai cara yang tidak kompatibel). Pola yang digunakan adalah pola globbing nama file standar.

Masalah yang Anda hadapi disebabkan oleh fakta bahwa _karakter yang valid dalam nama variabel. Shell dengan demikian akan melihat *_$testseq_*" *_diikuti oleh nilai variabel $testseq_dan *". Variabel $testseq_tidak terdefinisi, sehingga akan diperluas ke string kosong, dan Anda berakhir dengan *_*, yang jelas cocok dengan $filenilai yang Anda miliki. Anda mungkin berharap mendapatkan Trueselama nama file dalam $filemengandung setidaknya satu garis bawah.

Untuk benar membatasi nama variabel, penggunaan "..."sekitar ekspansi: *_"$testseq"_*. Ini akan menggunakan nilai variabel sebagai string. Jika Anda ingin menggunakan nilai variabel sebagai pola , gunakan *_${testseq}_*saja.

Perbaikan cepat lainnya adalah dengan memasukkan garis bawah dalam nilai $testseq:

testseq="_gen_"

dan kemudian gunakan saja *"$testseq"*sebagai pola (untuk perbandingan string).


Jadi shell akan mencari variabel $ testseq_ dan tidak menemukannya dan menggantinya dengan string kosong.
Viesturs

@ Viesturs Itulah inti masalahnya, ya.
Kusalananda

1
Untuk substring pencarian itu harus *"$testseq"*untuk caseseperti untuk [[...]](kecuali untuk zsh kecuali jika Anda mengaktifkan globsubst)
Stéphane Chazelas
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.