Costringere Bash a utilizzare il motore PerEx RegEx


11

Come forse già saprai, molte delle funzionalità supportate dai moderni motori RegEx (riferimenti secondari, asserzioni lookaround, ecc.) Non sono supportate dal motore Bash RegEx. Di seguito è riportato un semplice script Bash che ho appena creato per cercare di spiegare qual è il mio obiettivo finale:

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

Ad esempio, qualcosa come il seguente comando restituirà false:

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

mentre la stessa identica espressione troverà una corrispondenza quando usata in un tester regex Perl o JavaScript.

Anche i backreferences (ad es. (Expr1) (expr2) [] \ 1 \ 2) non corrispondono.

Sono semplicemente giunto alla conclusione che il mio problema sarà risolto solo quando costringo Bash a utilizzare un motore RegEx compatibile con Perl. È fattibile? In tal caso, come farei per eseguire la procedura?


5
Perché non usi semplicemente perl invece di bash per gli script? E perché questa domanda è taggata javascript?
Marco,

Perché usare Bash è un must nella mia situazione. E ho taggato accidentalmente JavaScript. L'ho rimosso :)
Fadi Hanna AL-Kass il

2
Perché non si usa grepcon -Po utilizzando sed?
cuonglm,

2
Ma non spieghi mai la situazione / problema che ti ha portato alla conclusione che devi fare in modo che la shell faccia qualcosa che semplicemente non può fare. Ci sarà un modo migliore.
llua,

Trovo che backreferences fanno il lavoro in bash 4.3.x (Ubuntu 14.04), ma non in bash 3.2x (OS X). Ecco il mio comando di prova:re="([a-z])[0-9]\1"; [[ a1a =~ $re ]] && echo ${BASH_REMATCH[0]}
Trauma digitale

Risposte:


14

Bash non supporta un metodo per farlo in questo momento. Ti rimangono le seguenti opzioni:

  1. Usa Perl
  2. Uso grep [-P|--perl-regexp]
  3. Usa la funzionalità Bash per codificarlo

Penso che vorrei andare con il n. 2 e provare e usare grepper ottenere ciò che voglio funzionalmente. Per i riferimenti secondari è possibile effettuare le seguenti operazioni con 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 

Riferimenti


Onestamente non sapevo che grep avesse un [-P|--perl-regexp]token. Grazie mille :-)
Fadi Hanna AL-Kass,

@ FadiHannaAL-Kass - di niente. Grazie per la domanda
slm

2
Per i posteri, solo GNU grep include l' -Popzione e non è universale. Il grep di FreeBSD si basa su GNU, ma la documentazione afferma "Questa opzione non è supportata in FreeBSD". In OSX, grep si basa anche su GNU, ma l' -Popzione non è nemmeno menzionata nella pagina man. E su altri sistemi unix il cui grep non è GNU, è improbabile che tu veda da -Pnessuna parte. Se esiste la remota possibilità che la portabilità possa esserti utile in futuro, ti consiglio di evitare opzioni specifiche del sistema operativo come questa.
ghoti,

pcregrepè anche un'opzione, se disponibile.
Carattere jolly

Va notato che zsh fa esattamente ciò che l'OP ha richiesto, purché l' REMATCH_PCREopzione sia impostata.
Tim Peoples,

0

Uno potrebbe usare pcregrep. Viene fornito con il pacchetto pcrein CentOS e pcregrepin Ubuntu.

grep -P potrebbe avere questo problema a seconda del sistema operativo / versione:

-P, --perl-regexp
              Interpret PATTERN as a Perl regular expression.  This is highly experimental and grep -P may warn of unimplemented features.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.