Memaksa Bash untuk menggunakan Mesin Perl RegEx

11

Seperti yang mungkin sudah Anda ketahui, banyak fitur yang didukung oleh mesin RegEx modern (referensi balik, pernyataan lookaround, dll.) Tidak didukung oleh mesin Bash RegEx. Berikut ini adalah skrip Bash sederhana yang baru saja saya buat untuk mencoba menjelaskan apa tujuan akhir saya:

#!/bin/bash

# Make sure exactly two arguments are passed.
if [ $# -lt 2 ]
then
    echo "Usage: match [string] [pattern]"
    return
fi

variable=${1}
pattern=${2}

if [[ ${variable} =~ ${pattern} ]]
then
    echo "true"
else
    echo "false"
fi

Jadi misalnya, sesuatu seperti perintah berikut ini akan kembali salah:

. match.sh "catfish" "(?=catfish)fish"

sedangkan ekspresi yang sama persis akan menemukan kecocokan saat digunakan dalam Perl atau penguji regex JavaScript.

Referensi balik (mis. (Expr1) (expr2) [] \ 1 \ 2) tidak akan cocok juga.

Saya hanya sampai pada kesimpulan bahwa masalah saya hanya akan diselesaikan ketika memaksa bash untuk menggunakan mesin RegEx yang kompatibel dengan Perl. Apakah ini bisa dilakukan? Jika demikian, bagaimana saya menjalankan prosedur?

Fadi Hanna AL-Kass
sumber
5
Mengapa Anda tidak menggunakan perl saja alih-alih bash untuk skrip? Dan mengapa pertanyaan ini ditandai dengan javascript?
Marco
Karena menggunakan Bash adalah suatu keharusan dalam situasi saya. Dan saya tidak sengaja menandai JavaScript. Saya menghapusnya :)
Fadi Hanna AL-Kass
2
Mengapa Anda tidak menggunakan grepdengan -Patau menggunakan sed?
cuonglm
2
Tetapi Anda tidak pernah menjelaskan situasi / masalah yang membuat Anda sampai pada kesimpulan bahwa Anda harus membuat shell melakukan sesuatu yang tidak bisa dilakukan. Ada cara yang lebih baik.
llua
Saya menemukan bahwa backreferences melakukan pekerjaan di bash 4.3.x (Ubuntu 14.04), tetapi tidak di bash 3.2x (OS X). Ini adalah perintah pengujian saya:re="([a-z])[0-9]\1"; [[ a1a =~ $re ]] && echo ${BASH_REMATCH[0]}
Digital Trauma

Jawaban:

14

Bash tidak mendukung metode bagi Anda untuk melakukan ini saat ini. Anda memiliki opsi berikut:

  1. Gunakan Perl
  2. Menggunakan grep [-P|--perl-regexp]
  3. Gunakan fungsi Bash untuk mengkodekannya

Saya pikir saya akan pergi dengan # 2 dan mencoba dan gunakan grepuntuk mendapatkan apa yang saya inginkan secara fungsional. Untuk referensi balik Anda dapat melakukan hal berikut dengan grep:

$ echo 'BEGIN `helloworld` END' | grep -oP '(?<=BEGIN `).*(?=` END)'
helloworld

-o, --only-matching       show only the part of a line matching PATTERN
-P, --perl-regexp         PATTERN is a Perl regular expression

(?=pattern)
    is a positive look-ahead assertion
(?!pattern)
    is a negative look-ahead assertion
(?<=pattern)
    is a positive look-behind assertion
(?<!pattern)
    is a negative look-behind assertion 

Referensi

slm
sumber
Jujur saya tidak tahu grep punya [-P|--perl-regexp]token. Terima kasih banyak :-)
Fadi Hanna AL-Kass
@ FadiHannaAL-Kass - sama-sama Terima kasih untuk pertanyaannya.
slm
2
Untuk anak cucu, hanya GNU grep yang menyertakan -Popsi, dan itu tidak universal. Grep FreeBSD didasarkan pada GNU, tetapi dokumentasi menyatakan "Opsi ini tidak didukung dalam FreeBSD". Di OSX, grep juga didasarkan pada GNU, tetapi -Popsi bahkan tidak disebutkan di halaman manual. Dan pada sistem unix lain yang grep bukan GNU, Anda tidak mungkin melihat -Pdi mana pun. Jika ada kemungkinan jauh Anda bahwa portabilitas mungkin berguna bagi Anda di masa depan, saya sarankan menghindari opsi spesifik OS seperti ini.
ghoti
pcregrepjuga merupakan opsi, jika tersedia.
Wildcard
Perlu dicatat bahwa zsh melakukan persis apa yang diminta OP, selama REMATCH_PCREopsi tersebut ditetapkan.
Tim Peoples
0

Orang bisa menggunakan pcregrep. Muncul dengan paket pcredi CentOS dan pcregrepdi Ubuntu.

grep -P dapat memiliki masalah ini tergantung pada OS / versi:

-P, --perl-regexp
              Interpret PATTERN as a Perl regular expression.  This is highly experimental and grep -P may warn of unimplemented features.
site80443
sumber