Tes Bash: apa yang dilakukan “= ~”?

40
#!/bin/bash
INT=-5

if [[ "$INT" =~ ^-?[0-9]+$ ]]; then

echo "INT is an integer."

else

echo "INT is not an integer." >&2

exit 1

fi

Apa yang dilakukan pemimpin ~dalam ekspresi reguler awal?

Ragnarok
sumber
3
Ini bukan regex, ini adalah pola ujian untuk menentukan pertandingan regex ...
jasonwryan
5
Sudahkah Anda membaca manual bash? Apa yang Anda temukan tidak jelas?
icarus
3
Cari halaman bash man untuk = ~
Jeff Schaller

Jawaban:

46

The ~sebenarnya adalah bagian dari operator =~yang melakukan pertandingan ekspresi reguler dari string ke kiri untuk ekspresi reguler diperpanjang pada haknya.

[[ "string" =~ pattern ]]

Perhatikan bahwa string harus dikutip, dan ungkapan reguler tidak boleh dikutip.

Operator serupa digunakan dalam bahasa pemrograman Perl.

Ekspresi reguler yang dipahami oleh bashadalah sama dengan yang grepdipahami GNU dengan -Ebendera, yaitu serangkaian ekspresi reguler yang diperluas.


Agak di luar topik, tetapi baik untuk diketahui:

Saat mencocokkan dengan ekspresi reguler yang berisi grup penangkap, bagian dari string yang ditangkap oleh setiap grup tersedia dalam BASH_REMATCHarray. The zeroth / pertama entri dalam array ini bersesuaian dengan &pola penggantian sed's perintah substitusi (atau $&di Perl), yang merupakan sedikit dari string yang cocok dengan pola, sedangkan entri pada indeks 1 dan seterusnya sesuai dengan \1, \2, dll . dalam sedpola penggantian (atau $1, $2dll dalam Perl), yaitu bit yang cocok dengan masing-masing tanda kurung.

Contoh:

string=$( date +%T )

if [[ "$string" =~ ^([0-9][0-9]):([0-9][0-9]):([0-9][0-9])$ ]]; then
  printf 'Got %s, %s and %s\n' \
    "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}" "${BASH_REMATCH[3]}"
fi

Ini dapat menghasilkan

Got 09, 19 and 14

jika waktu saat ini adalah 09:19:14.

The REMATCHbit dari BASH_REMATCHnama array berasal dari "Regular Expression Match", yaitu "RE-Match".


Dalam bashcangkang non -Bourne-like, seseorang juga dapat menggunakan expruntuk pencocokan ekspresi reguler terbatas (hanya menggunakan ekspresi reguler dasar).

Contoh kecil:

$ string="hello 123 world"
$ expr "$string" : ".*[^0-9]\([0-9][0-9]*\)"
123
Kusalananda
sumber
2
Itu sama dengan apa yang grep -Ehanya mengerti pada sistem GNU dan hanya ketika menggunakan variabel yang tidak dikutip sebagai pola [[ $var = $pattern ]](lihat [[ 'a b' =~ a\sb ]]vs p='a\sb'; [[ 'a b' =~ $p ]]). Juga berhati-hatilah bahwa mengutip shell mempengaruhi arti dari operator RE dan bahwa beberapa karakter perlu dikutip untuk tokenisasi shell yang mungkin mempengaruhi pemrosesan RE. [[ '\' =~ [\/] ]]mengembalikan salah. ksh93memiliki masalah yang lebih buruk. Lihat zsh(atau bash 3.1) untuk pendekatan yang lebih waras di mana shell dan kutipan RE jelas terpisah. The [builtin dari zshdan yashjuga memiliki =~operator.
Stéphane Chazelas
2
sangat keren off-topic! +1 (
JJoao
@ StéphaneChazelas Bagaimana "saner" yang cocok dengan keduanya di zsh ?: [[ "This is a fine mess." =~ T.........fin*es* ]]; [[ "This is a fine mess." =~ T.........fin\*es\* ]]. Atau yang dikutip *juga cocok? [[ "This is a fine mess." =~ "T.........fin*es*" ]].
sorontar
Ini lebih waras (IMO) karena aturannya jauh lebih sederhana. Shell mengutip dan RE melarikan diri jelas terpisah. Dalam [[ a =~ .* ]]atau [[ a =~ '.*' ]]atau [[ a =~ \.\* ]], .*RE yang sama diteruskan ke =~operator. OTH, dalam bash, [[ '\' =~ [)] ]]mengembalikan kesalahan, apakah Anda tahu tanpa mencobanya apakah [[ '\' =~ [\)] ]]cocok? Bagaimana [[ '\' =~ [\/] ]](itu tidak di ksh93). Bagaimana dengan c='a-z'; [[ a =~ ["$c"] ]](bandingkan dengan =operator)? Lihat juga: [[ '\' =~ [^]"."] ]]yang mengembalikan palsu ... Catatan bahwa Anda dapat melakukan shopt -s compat31di bashuntuk mendapatkan zshperilaku.
Stéphane Chazelas
zsh/ bash -o compat31'S perilaku untuk [[ a =~ '.*' ]]juga konsisten dengan [ a '=~' '.*' ](untuk [implementasi bahwa dukungan =~) atau expr a : '.*'. OTOH, itu tidak konsisten dengan [[ a = '*' ]]vs [[ a = * ]](tapi kemudian, gumpalan adalah bagian dari bahasa shell, sementara RE tidak).
Stéphane Chazelas
4

Anda harus membaca halaman bash man, di bawah [[ expression ]]bagian.

An additional binary operator, =~, is available, with the same precedence as == and !=. When it is used, the string to the right of the operator is considered an extended regular expression and matched accordingly (as in regex(3)).

Singkatnya, =~adalah operator, seperti ==dan !=. Itu tidak ada hubungannya dengan regex aktual di string di sebelah kanannya.

Sokel
sumber
Bisakah Anda mencari tahu beberapa contoh yang menunjukkan penggunaan =~dalam kehidupan nyata ...?
George Vasiliou
1
@ GeorgeVasiliou Saya cukup sering menggunakannya dalam skrip yang menempatkan output dari perintah ke dalam variabel. Kemudian variabel diperiksa untuk melihat apakah itu cocok dengan beberapa pola string. Ini berguna misalnya jika Anda ingin mengambil tindakan berdasarkan pada beberapa output kesalahan dari perintah itu.
Michael Martinez
@ Sokel Bagi sebagian orang, "RTFM" lebih mudah diucapkan daripada dilakukan. ⋯ man [[ expresssion ]]dan man [[tidak mengembalikan apa pun. help [[mengembalikan informasi yang berguna — karena [[perintah bash internal — tetapi tidak mengatakan apakah =~menggunakan sintaks regex dasar atau diperluas. ⋯ Teks yang Anda kutip adalah dari halaman bash man. Saya menyadari Anda mengatakan "baca halaman bash man" tetapi pada awalnya, saya pikir Anda bermaksud membaca halaman man dalam bash. Bagaimanapun, man bashmengembalikan file besar, yang 4139 baris (72 halaman). Itu dapat dicari dengan menekan /▒▒▒, yang membutuhkan regex, yang rasanya — seperti =~— tidak ditentukan.
Alex Quinn