Buộc Bash sử dụng Perl RegEx Engine


11

Như bạn có thể đã biết, rất nhiều tính năng hỗ trợ các công cụ RegEx hiện đại (tham chiếu lại, xác nhận tìm kiếm, v.v.) không được hỗ trợ bởi công cụ Bash RegEx. Sau đây là một kịch bản Bash đơn giản mà tôi vừa tạo để cố gắng giải thích mục tiêu cuối cùng của tôi là gì:

#!/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

Vì vậy, ví dụ, một cái gì đó như lệnh sau sẽ trả về false:

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

trong khi đó cùng một biểu thức sẽ tìm thấy sự trùng khớp khi được sử dụng trong Perl hoặc trình kiểm tra regex JavaScript.

Backreferences (ví dụ (expr1) (expr2) [] \ 1 \ 2) cũng sẽ không khớp.

Tôi chỉ đơn giản là đi đến kết luận rằng vấn đề của tôi sẽ chỉ được giải quyết khi buộc bash sử dụng công cụ RegEx tương thích với Perl. Đây có phải là có thể làm được? Nếu vậy, làm thế nào tôi sẽ thực hiện các thủ tục?


5
Tại sao bạn không sử dụng perl thay vì bash cho script? Và tại sao câu hỏi này được gắn thẻ javascript?
Marco

Bởi vì sử dụng Bash là điều bắt buộc trong tình huống của tôi. Và tôi đã vô tình gắn thẻ JavaScript. Tôi đã xóa nó :)
Fadi Hanna AL-Kass

2
Tại sao bạn không sử dụng grepvới -Phoặc sử dụng sed?
cuonglm

2
Nhưng bạn không bao giờ giải thích tình huống / vấn đề khiến bạn đi đến kết luận rằng bạn phải có cái vỏ làm điều gì đó đơn giản là không thể làm được. Có một cách tốt hơn.
llua

Tôi thấy rằng backreferences làm việc trong bash 4.3.x (Ubuntu 14.04), nhưng không phải trong bash 3.2x (OS X). Đây là lệnh thử nghiệm của tôi:re="([a-z])[0-9]\1"; [[ a1a =~ $re ]] && echo ${BASH_REMATCH[0]}
Chấn thương kỹ thuật số

Câu trả lời:


14

Bash không hỗ trợ một phương pháp để bạn làm điều này tại thời điểm này. Bạn còn lại với các tùy chọn sau:

  1. Sử dụng Perl
  2. Sử dụng grep [-P|--perl-regexp]
  3. Sử dụng chức năng Bash để mã hóa nó

Tôi nghĩ rằng tôi sẽ đi với # 2 và thử và sử dụng grepđể có được những gì tôi muốn một cách chức năng. Để tham khảo lại, bạn có thể làm như sau với 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 

Người giới thiệu


Tôi thực sự không biết grep có [-P|--perl-regexp]mã thông báo. Cảm ơn rất nhiều :-)
Fadi Hanna AL-Kass

@ FadiHannaAL-Kass - bạn được chào đón. Cảm ơn câu hỏi.
slm

2
Đối với hậu thế, chỉ có GNU grep bao gồm -Ptùy chọn và nó không phổ biến. Grep của FreeBSD dựa trên GNU, nhưng tài liệu ghi rõ "Tùy chọn này không được hỗ trợ trong FreeBSD". Trong OSX, grep cũng dựa trên GNU, nhưng -Ptùy chọn thậm chí không được đề cập trong trang man. Và trên các hệ thống unix khác có grep không phải là GNU, bạn hoàn toàn không thể thấy -Pbất cứ nơi nào. Nếu có khả năng từ xa cho bạn rằng tính di động có thể hữu ích cho bạn trong tương lai, tôi khuyên bạn nên tránh các tùy chọn dành riêng cho hệ điều hành như thế này.
ghoti

pcregrepcũng là một lựa chọn, nếu có sẵn
tự đại diện

Cần lưu ý rằng zsh thực hiện chính xác những gì OP yêu cầu, miễn là REMATCH_PCREtùy chọn được đặt.
Tim nhân dân

0

Người ta có thể sử dụng pcregrep. Nó đi kèm với gói pcretrong CentOS và pcregreptrong Ubuntu.

grep -P có thể có vấn đề này tùy thuộc vào hệ điều hành / phiên bản:

-P, --perl-regexp
              Interpret PATTERN as a Perl regular expression.  This is highly experimental and grep -P may warn of unimplemented features.
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.