Ekspresi reguler dalam skrip bash

13

Ini adalah pertama kalinya bash scripting saya jadi saya mungkin membuat kesalahan mudah.

Pada dasarnya, saya mencoba menulis skrip yang mendapatkan grup pengguna, dan jika mereka berada dalam grup tertentu, itu akan mencatatnya. Jelas akan ada lebih banyak fungsi, tetapi tidak ada gunanya membangun bahwa ketika saya bahkan tidak bisa membuat regex berfungsi!

Sejauh ini, saya punya ini:

#!/bin/bash

regex="^([a-zA-Z0-9\-_]+ : [a-zA-Z0-9\-_]+) (usergroup)$"

# example output
groups="username : username usergroup"

echo "$groups" >> /home/jrdn/log

if [[ "$groups" =~ $regex ]]; then
    echo "Match!" >> /home/jrdn/log
else
    echo "No match" >> /home/jrdn/log
fi

Setiap tempat saya sudah mencoba regex itu, itu berhasil. Tetapi dalam skrip bash, hanya akan menghasilkan $groups, diikuti oleh No match. Jadi bisakah seseorang memberi tahu saya apa yang salah dengannya?

jrdn
sumber
1
Apa yang membuat Anda berpikir ada yang salah dengan itu?
manatwork
1
@jrdnhannah kemudian coba untuk perlahan menciptakan kembali regexp target Anda, pertandingan pertama ^([a-zA-Z0-9\-_]+)kemudian tambahkan titik dua dan seterusnya ... Anda harus segera mengetahuinya, di mana masalahnya.
peterph
2
Sama di sini dengan bash 4.2.45. Lolos dari garis bawah diperbaiki. Aneh. @jrdnhannah dapatkah Anda menuliskannya sebagai jawaban dan menerimanya?
terdon
1
Karena saya baru saja mendaftar ke Unix SE, saya harus menunggu 8 jam sebelum menjawab sendiri. Senang menandainya sebagai dijawab jika orang lain melakukannya.
jrdn
4
@terdon bash hanya memanggil fungsi regex libc, mungkin. Jadi itu tergantung pada versi libc, bukan versi bash. Lihat jawaban saya ... (Atau mungkin bahkan pada urutan pemeriksaan yang Anda gunakan)
derobert

Jawaban:

14

Dari man 7 regex:

Ekspresi kurung adalah daftar karakter yang dilampirkan dalam "[]". ...

… Untuk memasukkan literal '-', jadikan itu karakter pertama atau terakhir…. [A] ll karakter khusus lainnya, termasuk '\', kehilangan arti khusus mereka dalam ekspresi braket.

Mencoba regexp dengan egrep memberikan kesalahan:

$ echo "username : username usergroup" | egrep "^([a-zA-Z0-9\-_]+ : [a-zA-Z0-9\-_]+) (usergroup)$"
egrep: Invalid range end

Ini adalah versi yang lebih sederhana, yang juga memberikan kesalahan:

$ echo 'hi' | egrep '[\-_]'
egrep: Invalid range end

Karena \tidak spesial, itu adalah kisaran, seperti yang [a-z]akan terjadi. Anda harus meletakkannya -di akhir, seperti [_-]atau:

echo "username : username usergroup" | egrep "^([a-zA-Z0-9_-]+ : [a-zA-Z0-9_-]+) (usergroup)$"
username : username usergroup

Ini harus bekerja terlepas dari versi libc Anda (baik dalam egrep atau bash).

sunting: Ini sebenarnya tergantung pada pengaturan lokal Anda juga. Halaman manual memang memperingatkan tentang ini:

Rentang sangat tergantung pada urutan, dan program portabel harus menghindari mengandalkannya.

Sebagai contoh:

$ echo '\_' | LC_ALL=en_US.UTF8 egrep '[\-_]'
egrep: Invalid range end
$ echo '\_' | LC_ALL=C egrep '[\-_]'
\_

Tentu saja, meskipun tidak salah, itu tidak melakukan apa yang Anda inginkan:

$ echo '\^_' | LC_ALL=C egrep '^[\-_]+$'
\^_

Ini berbagai, yang dalam ASCII, termasuk \, [, ^, dan _.

derobert
sumber
Menarik. My egreptidak memberikan kesalahan, cukup cocokkan dengan benar.
manatwork
@manatwork urutan pemeriksaan Anda mungkin memungkinkan kisaran ....
derobert
Saya tidak tahu banyak tentang susunan. Maksudmu ini LC_COLLATE="en_US.UTF-8":?
manatwork
@manatwork Saya telah mengedit pertanyaan untuk memberikan contoh. Perhatikan bahwa ini mungkin berbeda pada sistem Anda, karena kadang-kadang urutan susunan (penyortiran) tersebut berubah.
derobert
1
@manatwork Tidak apa-apa, saya hampir mengajukan laporan bug sebelum saya perhatikan upaya untuk melarikan diri -...
derobert
4

Aturan umum dengan regexps (dan bug apa pun dalam potongan kode yang lebih besar): kurangi dan bangun kembali langkah demi langkah atau gunakan membagi dua - apa pun yang lebih baik untuk Anda.

Dalam hal ini pelakunya ternyata adalah garis bawah - melarikan diri dengan backslash membuatnya berhasil.

peterph
sumber