Заставить Bash использовать Perl RegEx Engine

11

Как вы, возможно, уже знаете, многие функции, поддерживаемые современными механизмами RegEx (обратные ссылки, обходные утверждения и т. Д.), Не поддерживаются механизмом Bash RegEx. Ниже приведен простой скрипт Bash, который я только что создал, чтобы попытаться объяснить, какова моя конечная цель:

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

Так, например, что-то вроде следующей команды вернет false:

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

тогда как точно такое же выражение найдет совпадение при использовании в Perl или в тестере регулярных выражений JavaScript.

Обратные ссылки (например, (expr1) (expr2) [] \ 1 \ 2) также не будут совпадать.

Я просто пришел к выводу, что моя проблема будет решена, только если заставить bash использовать Perl-совместимый движок RegEx. Это выполнимо? Если так, как бы я пошла на выполнение процедуры?

Фади Ханна АЛ-Касс
источник
5
Почему бы вам не использовать Perl вместо Bash для сценариев? И почему этот вопрос помечен javascript?
Марко
Потому что использование Bash является обязательным в моей ситуации. И я случайно пометил JavaScript. Я снял его :)
Фади Ханна АЛ-Касс
2
Почему вы не используете grepс -Pили используете sed?
Cuonglm
2
Но вы никогда не объясняете ситуацию / проблему, из-за которой вы пришли к выводу, что оболочка должна делать то, чего она просто не может сделать. Там быть лучше.
Луа
Я считаю , что обратные_связи сделать работу в Баш 4.3.x (Ubuntu 14.04), но не в Баш 3.2x (OS X). Вот моя тестовая команда:re="([a-z])[0-9]\1"; [[ a1a =~ $re ]] && echo ${BASH_REMATCH[0]}
Цифровая травма

Ответы:

14

Bash не поддерживает метод для вас сделать это в настоящее время. У вас остались следующие варианты:

  1. Используйте Perl
  2. использование grep [-P|--perl-regexp]
  3. Используйте функциональность Bash для его кодирования

Я думаю, я бы пошел с # 2 и попытался бы использовать grepто, что я хочу функционально. Для обратной ссылки вы можете сделать следующее 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 

Ссылки

SLM
источник
Честно говоря, я не знал, что у Грепа был [-P|--perl-regexp]токен. Большое спасибо :-)
Фади Ханна AL-Kass
@ FadiHannaAL-Kass - пожалуйста. Спасибо за вопрос.
СЛМ
2
Для потомков, только GNU grep включает эту -Pопцию, и она не универсальна. Grep во FreeBSD основан на GNU, но в документации говорится: «Этот параметр не поддерживается во FreeBSD». В OSX grep также основан на GNU, но эта -Pопция даже не упоминается на странице руководства. А в других системах Unix, в которых grep не является GNU, вы вряд ли сможете увидеть его -Pгде-либо вообще. Если существует вероятность того, что переносимость может быть полезна для вас в будущем, я рекомендую избегать таких опций, специфичных для ОС, как этот.
Готи
pcregrepтакже вариант, если имеется.
Wildcard
Следует отметить, что zsh делает именно то, что запрашивал OP, при условии, что REMATCH_PCREопция установлена.
Тим
0

Можно использовать pcregrep. Поставляется с пакетом pcreв CentOS и pcregrepв Ubuntu.

grep -P может иметь эту проблему в зависимости от ОС / версии:

-P, --perl-regexp
              Interpret PATTERN as a Perl regular expression.  This is highly experimental and grep -P may warn of unimplemented features.
site80443
источник